zoukankan      html  css  js  c++  java
  • vue服务端渲染axios预取数据

    首先是要参考vue服务端渲染教程:https://ssr.vuejs.org/zh/data.html。

    本文主要代码均参考教程得来。基本原理如下,拷贝的原文教程。

    为了解决这个问题,获取的数据需要位于视图组件之外,即放置在专门的数据预取存储容器(data store)或"状态容器(state container))"中。首先,在服务器端,我们可以在渲染之前预取数据,并将数据填充到 store 中。此外,我们将在 HTML 中序列化(serialize)和内联预置(inline)状态。这样,在挂载(mount)到客户端应用程序之前,可以直接从 store 获取到内联预置(inline)状态。

    依据这段话,需要使用vuex;使用vuex的代码如下:

     1 import Vue from 'vue'
     2 import Vuex from 'vuex'
     3 Vue.use(Vuex)
     4 // 假定我们有一个可以返回 Promise 的
     5 // 通用 API(请忽略此 API 具体实现细节)
     6 import { fetchItem } from '../api'
     7 export function createStore () {
     8   return new Vuex.Store({
     9     state: {
    10       items: {}
    11     },
    12     actions: {
    13       fetchItem ({ commit }, id) {
    14         // `store.dispatch()` 会返回 Promise,
    15         // 以便我们能够知道数据在何时更新
    16         return fetchItem(id).then(item => {
    17           
    18           commit('setItem', { id, item })
    19         })
    20       }
    21     },
    22     mutations: {
    23       setItem (state, { id, item }) {
    24         Vue.set(state.items, id, item)
    25       }
    26     }
    27   })
    28 }

    上面的api中代码:

     1 import api from "create-api"
     2 export function fetchItem(id) {
     3 
     4   return new Promise(function(resolve, reject) {
     5     api.get("http://www.youxuewang.com.cn/shouji/home/LoadProducts", {
     6       pageno: 1,
     7       pagesize: 200,
     8       condstr: '社会大课堂:0'
     9     }).then(function(res) {
    10       resolve({ text: JSON.stringify(res)});
    11 
    12     }).catch(function() {
    13       console.log(222222222222222);
    14     });
    15   })
    16 
    17   //return Promise.resolve(obj)
    18 }
    create-api是webpack的别名也就是alias配置,实际是两个文件,服务端文件如下
     1 const isProd = process.env.NODE_ENV === 'production';
     2 
     3 const axios = require('axios');
     4 let host = isProd ? 'http://www.youxuewang.com.cn/shouji/home/LoadProducts' : 'http://www.youxuewang.com.cn/shouji/home/LoadProducts';
     5 let cook = process.__COOKIE__ || '';
     6 let api;
     7 
     8 axios.defaults.baseURL = host;
     9 axios.defaults.timeout = 10000;
    10 
    11 axios.interceptors.response.use((res) => {
    12   if (res.status >= 200 && res.status < 300) {
    13     console.log(121212,res.status );
    14     return res;
    15   }
    16   return Promise.reject(res);
    17 }, (error) => {
    18   // 网络异常
    19   return Promise.reject({message: '网络异常,请刷新重试', err: error, type: 1});
    20 });
    21 
    22 if (process.__API__) {
    23   api = process.__API__;
    24 } else {
    25   api = {
    26     get: function(target, options = {}) {
    27       return new Promise((resolve, reject) => {
    28         axios.request({
    29           url: target,
    30           method: 'get',
    31           headers: {
    32             'Cookie': cook
    33           },
    34           params: options
    35         }).then(res => {
    36           resolve(res.data);
    37         }).catch((error) => {
    38           reject(error);
    39         });
    40       });
    41     },
    42     post: function(target, options = {}) {
    43       return new Promise((resolve, reject) => {
    44         axios.request({
    45           url: target,
    46           method: 'post',
    47           headers: {
    48             'Cookie': cook
    49           },
    50           params: options
    51         }).then(res => {
    52           resolve(res.data);
    53         }).catch((error) => {
    54           reject(error);
    55         });
    56       });
    57     }
    58   };
    59 }
    60 
    61 module.exports = api;

    客户端用代码如下

     1 const axios = require('axios');
     2 let api;
     3 
     4 axios.defaults.timeout = 10000;
     5 
     6 //拦截器,使用拦截器提前对axios操控,before they are handled by then or catch.
     7 axios.interceptors.response.use((res) => {
     8   if (res.status >= 200 && res.status < 300) {
     9     console.log(22,res.status );
    10     return res;
    11   }
    12   return Promise.reject(res);
    13 }, (error) => {
    14   // 网络异常
    15   return Promise.reject({message: '网络异常,请刷新重试', err: error});
    16 });
    17 
    18 if (process.__API__) {
    19   api = process.__API__;
    20 } else {
    21   api = {
    22     get: function(target, params = {}) {
    23       const suffix = Object.keys(params).map(name => {
    24         return `${name}=${JSON.stringify(params[name])}`;
    25       }).join('&');
    26       const urls = `${target}?${suffix}`;
    27       return new Promise((resolve, reject) => {
    28         axios.get(urls, params).then(res => {
    29           resolve(res.data);
    30         }).catch((error) => {
    31           reject(error);
    32         });
    33       });
    34     },
    35     post: function(target, options = {}) {
    36       return new Promise((resolve, reject) => {
    37         axios.post(target, options).then(res => {
    38           resolve(res.data);
    39         }).catch((error) => {
    40           reject(error);
    41         });
    42       });
    43     }
    44   };
    45 }
    46 
    47 module.exports = api;

    那么,我们在哪里放置「dispatch 数据预取 action」的代码?

    我们需要通过访问路由,来决定获取哪部分数据 - 这也决定了哪些组件需要渲染。事实上,给定路由所需的数据,也是在该路由上渲染组件时所需的数据。所以在路由组件中放置数据预取逻辑,是很自然的事情

    我们将在路由组件上暴露出一个自定义静态函数 asyncData。注意,由于此函数会在组件实例化之前调用,所以它无法访问 this。需要将 store 和路由信息作为参数传递进去。

    上面这句话,诞生了服务端渲染数据的路由组件有一个asyncData方法,代码如下

     1 <template>
     2   <div>{{ item.text }}---{{fooCount}}</div>
     3 </template>
     4 <script>
     5 // 在这里导入模块,而不是在 `store/index.js` 中
     6 import fooStoreModule from '../store/modules/foo'
     7 export default {
     8   asyncData ({ store,route}) {
     9     store.registerModule('foo', fooStoreModule)
    10     //return store.dispatch('foo/inc')
    11     return Promise.all([
    12         store.dispatch("fetchItem",route.params.id),
    13         store.dispatch('foo/inc')
    14       ])
    15   },
    16   // 重要信息:当多次访问路由时,
    17   // 避免在客户端重复注册模块。
    18   destroyed () {
    19     this.$store.unregisterModule('foo')
    20   },
    21   computed: {
    22     fooCount () {
    23       return this.$store.state.foo.count
    24     },item () {
    25       return this.$store.state.items[this.$route.params.id]
    26     }
    27   }
    28 }
    29 </script> 

    主要代码介绍如上,完成代码github链接:https://github.com/mstzhen/vue-ssr-axios。

    预取数据演示访问地址:http://localhost:8080/item/22;

    本文结束。

  • 相关阅读:
    输入流输出流打印到文件
    前缀和
    树形dp
    快速幂 ,快速幂优化,矩形快速幂(java)
    尾递归
    java中bigInteger的应用
    求树的最大直径
    买不到的数目
    ccpc 长春站 G
    大学ACM第二周心得
  • 原文地址:https://www.cnblogs.com/zhensg123/p/9011653.html
Copyright © 2011-2022 走看看