当前位置 主页 > 服务器问题 > Linux/apache问题 >

    Egg Vue SSR 服务端渲染数据请求与asyncData

    栏目:Linux/apache问题 时间:2019-11-24 18:22

    服务端渲染 Node 层直接获取数据

    在 Egg 项目如果使用模板引擎规范时通是过 render 方法进行模板渲染,render 的第一个参数模板路径,第二个参数时模板渲染数据. 如如下调用方式:

    async index(ctx) {
      // 获取数据,可以是从数据库,后端 Http 接口 等形式
      const list = ctx.service.article.getArtilceList();
      // 对模板进行渲染,这里的 index.js 是 vue 文件通过 Webpack 构建的 JSBundle 文件
      await ctx.render('index.js', { list });
    }
    

    从上面的例子可以看出,这种使用方式是非常典型的也容易理解的模板渲染方式。在实际业务开发时,对于常规的页面渲染也建议使用这种方式获取数据没,然后进行页面渲染。Node 获取数据后,在 Vue 的根 Vue 文件里面就可以通过 this.list 的方式拿到 Node 获取的数据,然后就可以进行 vue 模板文件数据绑定了。

    在这里有个高阶用法,可以直接把 ctx 等 Node 对象传递到 第二个参数里面,  这个时候你在模板里面就直接拿到 ctx 这些对象。 但这个时候就需要自己处理好 SSR 渲染时导致的 hydrate 问题,因为前端hydrate时并没有 ctx 对象。 

    async index(ctx) {
      // 获取数据,可以是从数据库,后端 Http 接口 等形式
      const list = ctx.service.article.getArtilceList();
      // 对模板进行渲染,这里的 index.js 是 vue 文件通过 Webpack 构建的 JSBundle 文件
      await ctx.render('index.js', { ctx, list });
    }
    
    

    服务端渲染 asyncData 方式获取数据

    在 Vue 单页面 SSR 时涉及数据的请求方式,Node 层获取数据方式可以继续使用,但当路由切换时(页面直接刷新),Node 层就需要根据路由获取不同页面的数据,同时还要考虑前端路由切换的情况,这个时候路由是不会走 Node 层路由,而是直接进行的前端路由,这个时候也要考虑数据的请求方式。

    基于以上使用的优雅问题,这里提供一种 asyncData 获取数据的方式解决单页面 SSR 刷新不走 SSR 问题。 Node 不直接获取数据,获取数据的代码直接写到前端代码里面。这里需要解决如下两个问题:

    前端路由匹配 asyncData 调用

    这里根据路由切换 url 获取指定的路由 componet 组件,然后检查是否有 aysncData,如果有就进行调用。调用之后,数据会放到 Vuex 的 store 里面。

    return new Promise((resolve, reject) => {
        router.onReady(() => {
         // url 为当前请求路由,可以通过服务端传递到前端页面
         const matchedComponents = router.getMatchedComponents(url);
         if (!matchedComponents) {
          return reject({ code: '404' });
         }
         return Promise.all(
          matchedComponents.map(component => {
           // 关键代码
           if (component.methods && component.methods.asyncData) {
            return component.methods.asyncData(store);
           }
           return null;
          })
         ).then(() => {
          context.state = {
           ...store.state,
           ...context.state
          };
          return resolve(new Vue(options));
         });
        });
       });
    

    Vue 模板定义 asyncData 方法

    前端通过 Vuex 进行数据管理,把数据统一放到 store 里面,前端通过 this.$store.state 方式可以获取数据,Node 和 前端都可以获取到。

    <script type="text/babel">
     export default{
      computed: {
       isLoading(){
        return false;
       },
       articleList() {
        return this.$store.state.articleList;
       }
      },
      methods: {
       asyncData ({ state, dispatch, commit }) {
        return dispatch('FETCH_ARTICLE_LIST')
       }
      }
     }
    </script>