vue服務端渲染axios預取數據

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

本文主要代碼均參考教程得來。基本原理以下,拷貝的原文教程。vue

爲了解決這個問題,獲取的數據須要位於視圖組件以外,即放置在專門的數據預取存儲容器(data store)或"狀態容器(state container))"中。首先,在服務器端,咱們能夠在渲染以前預取數據,並將數據填充到 store 中。此外,咱們將在 HTML 中序列化(serialize)和內聯預置(inline)狀態。這樣,在掛載(mount)到客戶端應用程序以前,能夠直接從 store 獲取到內聯預置(inline)狀態。webpack

依據這段話,須要使用vuex;使用vuex的代碼以下:ios

 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中代碼:git

 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;

客戶端用代碼以下github

 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」的代碼?web

咱們須要經過訪問路由,來決定獲取哪部分數據 - 這也決定了哪些組件須要渲染。事實上,給定路由所需的數據,也是在該路由上渲染組件時所需的數據。因此在路由組件中放置數據預取邏輯,是很天然的事情vuex

咱們將在路由組件上暴露出一個自定義靜態函數 asyncData。注意,因爲此函數會在組件實例化以前調用,因此它沒法訪問 this。須要將 store 和路由信息做爲參數傳遞進去。axios

上面這句話,誕生了服務端渲染數據的路由組件有一個asyncData方法,代碼以下
api

 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;

本文結束。

相關文章
相關標籤/搜索