使用 Vue 增强现有的多页面/服务器呈现/经典网络应用程序

Using Vue to enhance existing Multi page / server rendered / classic web app

我已经搜索了几个小时,但没有找到任何与我的用例相近的东西。

body {
  background: #20262E;
  padding: 20px;
  font-family: Helvetica;
}

#app {
  background: #fff;
  border-radius: 4px;
  padding: 20px;
  transition: all 0.2s;
}

article {
  margin: 8px 0;
  background: #eee;
  padding: 20px;
}

h2 {
  font-weight: bold;
  margin-bottom: 15px;
}

del {
  color: rgba(0, 0, 0, 0.3);
}
<!-- server rendered -->
<div id="app">
  <h2>Freelance list</h2>
  
  <article>
    <h3>louane</h3>
    <p>
      City : <strong>courbevoie</strong>
      <br> Phone : <strong>05-36-23-51-89</strong>
    </p>
  </article>
  <article>
    <h3>indra</h3>
    <p>
      City : <strong>rheden</strong>
      <br> Phone : <strong>(354)-415-2419</strong>
    </p>
  </article>
  <article>
    <h3>angelo</h3>
    <p>
      City : <strong>montpreveyres</strong>
      <br> Phone : <strong>(883)-474-9314</strong>
    </p>
  </article>
  
  <a href="/prev-link">prev</a>
  <a href="/next-link">next</a>
</div>
<!-- server rendered -->

// fake url link, normally this would be taken from the href or something
var url = 'https://randomuser.me/api/?seed=abc&results=3&page=';
var page = 1;
var $articles = $('.articles');
var tpl = $articles.children().eq(0).clone();

$('.prev').click(function(e) {
 e.preventDefault();
  
  if (page <= 1) {
   return
  }

  page--;
  $.getJSON(url + page)
   .done(onReqDone);
});

$('.next').click(function(e) {
 e.preventDefault();

  page++;
  $.getJSON(url + page)
   .done(onReqDone);
});

function onReqDone(res) {
  $articles.html('');

  res.results.forEach(function(user) {
    var $node = tpl.clone();
    $node.find('h3').text(user.name.first);
    $node.find('strong:eq(0)').text(user.location.city);
    $node.find('strong:eq(1)').text(user.phone);
    $articles.append($node);
    window.scroll(0, 0);
  });

}
body {
  background: #20262E;
  padding: 20px;
  font-family: Helvetica;
}

#app {
  background: #fff;
  border-radius: 4px;
  padding: 20px;
  transition: all 0.2s;
}

article {
  margin: 8px 0;
  background: #eee;
  padding: 20px;
}

h2 {
  font-weight: bold;
  margin-bottom: 15px;
}

del {
  color: rgba(0, 0, 0, 0.3);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<!-- server rendered -->
<div id="app">
  <h2>Freelance list</h2>

  <div class="articles">
    <article>
      <h3>louane</h3>
      <p>
        City : <strong>courbevoie</strong>
        <br> Phone : <strong>05-36-23-51-89</strong>
      </p>
    </article>
    <article>
      <h3>indra</h3>
      <p>
        City : <strong>rheden</strong>
        <br> Phone : <strong>(354)-415-2419</strong>
      </p>
    </article>
    <article>
      <h3>angelo</h3>
      <p>
        City : <strong>montpreveyres</strong>
        <br> Phone : <strong>(883)-474-9314</strong>
      </p>
    </article>
  </div>

  <a href="/prev-link" class="prev">prev</a>
  <a href="/next-link" class="next">next</a>
</div>
<!-- server rendered -->

关于如何操作的任何想法?这是我的尝试: https://jsfiddle.net/7270zft3/2/ : 问题,它没有删除旧的 dom

PS : 在任何人谈论 Vue 的 SSR 或者只是做一个 SPA 之前,这就是我不能的原因:

您可以将 DOM ref 附加到服务器呈现的内容,然后就像在 jQuery 中一样,只需将内容清除到 DOM 元素。

您只需执行此操作一次,因此您可以添加检查以查看您的 DOM ref 是否为空 if page === 1

new Vue({
  el: "#app",
  data: {
    users: null,
    page: 1
  },
  methods: {
    loadData: function(prev) {
      var page = this.page

      if (prev) {
        page--
      } else {
        page++
      }

      fetch('https://randomuser.me/api/?seed=abc&results=3&page=' + page)
        .then(res => res.json())
        .then(data => {
          this.$refs.serverContent.innerHTML = '';
          this.users = data.results
          this.page = page
          window.scroll(0, 0)
        })
    }
  }
})
body {
  background: #20262E;
  padding: 20px;
  font-family: Helvetica;
}

#app {
  background: #fff;
  border-radius: 4px;
  padding: 20px;
  transition: all 0.2s;
}

article {
  margin: 8px 0;
  background: #eee;
  padding: 20px;
}

h2 {
  font-weight: bold;
  margin-bottom: 15px;
}

del {
  color: rgba(0, 0, 0, 0.3);
}
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<div id="app">
  <h2>Freelance list</h2>
  <div ref="serverContent">
    <article>
      <h3>louane</h3>
      <p>
        City : <strong>courbevoie</strong>
        <br> Phone : <strong>05-36-23-51-89</strong>
      </p>
    </article>
    <article>
      <h3>indra</h3>
      <p>
        City : <strong>rheden</strong>
        <br> Phone : <strong>(354)-415-2419</strong>
      </p>
    </article>
    <article>
      <h3>angelo</h3>
      <p>
        City : <strong>montpreveyres</strong>
        <br> Phone : <strong>(883)-474-9314</strong>
      </p>
    </article>
  </div>

  <!-- Vue part -->
  <!-- how to plug Vue to handle the pagination ? -->
  <article v-for="user in users">
    <h3>{{ user.name.first }}</h3>
    <p>
      City : <strong>{{ user.location.city }}</strong>
      <br> Phone : <strong>{{ user.phone }}</strong>
    </p>
  </article>
  <!-- Vue part -->

  <button v-show="page > 1" @click="loadData(true)">prev</button>
  <button @click="loadData()">next</button>
</div>
<!-- server rendered -->

但是要用Vue风格,建议你把第一页的渲染从服务器端去掉,让Vue自己处理data-fetching,这样Vue就可以使用它存储的data作为真相的来源,而不是操纵 DOM。

hydration的例子。我无法让 Vue 停止警告我生成的 HTML 与原始文件不匹配;这并不重要。在开发中,Vue 将 "bail and do a full render",但在生产中它将保留 pre-rendered。您只想确保它们匹配,这样当它确实更新时,它就是您所期望的。

我把 jQuery 留给了 getJSON。除此之外,它 jQuery 免费。

// fake url link, normally this would be taken from the href or something
var url = 'https://randomuser.me/api/?seed=abc&results=3&page=';
var page = 1;
$.getJSON(url + page).done((res) => {
  const articles = res.results;

  new Vue({
    el: '#app',
    template: `
  <div id="app">
    <h2>Freelance list</h2>
    <div class="articles">
      <article v-for="article in articles">
        <h3>{{article.name.first}}</h3>
        <p>
          City : <strong>{{article.location.city}}</strong>
          <br> Phone : <strong>{{article.phone}}</strong>
        </p>
      </article>
    </div>
    <a href="/prev-link" class="prev" @click.prevent="--page">prev</a>
    <a href="/next-link" class="next" @click.prevent="++page">next</a>
  </div>
  `,
    data: {
      page,
      url,
      articles
    },
    methods: {
      getPage() {
        $.getJSON(this.url + this.page)
          .done((res) => {
            this.articles = res.results;
          });
      }
    },
    watch: {
      page() {
        this.getPage();
      }
    }
  });
});
body {
  background: #20262E;
  padding: 20px;
  font-family: Helvetica;
}

#app {
  background: #fff;
  border-radius: 4px;
  padding: 20px;
  transition: all 0.2s;
}

article {
  margin: 8px 0;
  background: #eee;
  padding: 20px;
}

h2 {
  font-weight: bold;
  margin-bottom: 15px;
}

del {
  color: rgba(0, 0, 0, 0.3);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="//unpkg.com/vue@latest/dist/vue.js"></script>
<div id="app" data-server-rendered="true">
  <h2>Freelance list</h2>
  <div class="articles">
    <article>
      <h3>louane</h3>
      <p>
        City : <strong>courbevoie</strong>
        <br> Phone : <strong>05-36-23-51-89</strong>
      </p>
    </article>
    <article>
      <h3>indra</h3>
      <p>
        City : <strong>rheden</strong>
        <br> Phone : <strong>(354)-415-2419</strong>
      </p>
    </article>
    <article>
      <h3>angelo</h3>
      <p>
        City : <strong>montpreveyres</strong>
        <br> Phone : <strong>(883)-474-9314</strong>
      </p>
    </article>
  </div>

  <a href="/prev-link" class="prev">prev</a>
  <a href="/next-link" class="next">next</a>
</div>
<!-- server rendered -->

Vue 论坛上的某个人发现了一个与此处发布的内容接近但更适合我的需要的好方法:https://forum.vuejs.org/t/using-vue-to-enhance-existing-multi-page-server-rendered-classic-web-app/30934/20