说明


  基于 NuxtJS, 面向有 vue-cli 开发经验的宝宝。

 

目录

  

nuxt在store中使用axios nuxt loading_服务端

 

Nuxt

官方文档

简单来说,Nuxt就是基于Vue的一个应用框架,采用服务端渲染,让你的SPA应用(Vue)也可以拥有SEO

 

生命周期

众所周知,Vue 的生命周期全都跑在客户端(浏览器),而 Nuxt 的生命周期有些在服务端(Node),客户端,甚至两边都在:

nuxt在store中使用axios nuxt loading_nuxt在store中使用axios_02

生命周期流程图,红框内的是Nuxt的生命周期(运行在服务端),黄框内同时运行在服务端&&客户端上,绿框内则运行在客户端

 

实战经验

1. 红框、黄框内的周期都不存在 Window 对象

<script> 
    export default {   
        asyncData() {     
            console.log(window) // 服务端报错   
        },   
        fetch() {     
            console.log(window) // 服务端报错   
        },   
        created () {     
            console.log(window) // undefined   
        },   
        mounted () {     
            console.log(window) // Window {postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, frames: Window, …}   
        } 
    } 
</script>

 

2. 配置错误页面

你可以通过编辑 layouts/error.vue 文件来定制化错误页面

<template>   
    <div class="container">     
        <h1 v-if="error.statusCode === 404">页面不存在</h1>                     
        <h1 v-else>应用发生错误异常</h1>     
        <nuxt-link to="/">首 页</nuxt-link>   
    </div> 
</template> 

<script> 
    export default {  
        props: ['error'],   
        layout: 'blog' // 你可以为错误页面指定自定义的布局 
    } 
</script>

 

3. 自定义Loading页面

nuxt.config.js

module.exports = {   loading: '~components/loading.vue' }

 

loading.vue

<template>   
    <div class="loading-page" v-if="loading">     
        <p>Loading...</p>   
    </div> 
</template> 

<script> 
    export default {   
        data: () => ({     
            loading: false   
        }),   
        methods: {     
            start () {       
                this.loading = true    
            },     
            finish () {       
                this.loading = false     
            }   
        } 
    } 
</script>

 

4. 校验参数

如果校验失败,则自动跳转到错误页面

<script> 
export default {   
    validate({ params, query }) {     
        return /^d+$/.test(params.id) // must be number   
    } 
} 
</script>

 

5. Header、Footer等公共组件放哪?

大家都知道,vue-cli入口文件是app.vue,在nuxt开发当中则是**./layout/default.vue**

<template>   
    <div id="app">     
        <!-- 公共头部组件 -->     
        <xxx-header></xxx-header>     

        <!-- 路由视图,相当于router-view -->     
        <nuxt/>     

        <!-- 公共底部组件 -->     
        <xxx-footer></xxx-footer>   
    </div> 
</template>

 

6. 没有keep-alive

由于是服务端渲染,所以不支持组件的keep-alive,那自然activated、deactivated这两个生命周期也没了

 

7. 配置插件

所有插件都写在**/plugins目录下,这里以vue-lazyload**为例

plugins/lazy-load.js

import Vue from 'vue' 
import VueLazyLoad from 'vue-lazyload' 

Vue.use(VueLazyLoad, {   
    loading: require('~/assets/images/loading.jpg'),   
    error: require('~/assets/images/error.jpg') 
})

 

nuxt.config.js

module.expors = {   
    plugins = [     
        { src: "~/plugins/lazy-load", ssr: false }   
    ] 
}

 

8. 使用Axios,并配置全局拦截器,处理跨域

starter-template模板,推荐使用**@nuxtjs/axios、@nuxtjs/proxy**,不需要在plugins配置

安装依赖

npm install @nuxtjs/axios @nuxtjs/proxy --save

 

使用、处理跨域

// nuxt.config.js 
module.exports = {   
    modules: [ '@nuxtjs/axios' ], // 不需要加入@nuxtjs/proxy   
    axios: {     
        proxy: true,     
        prefix: '/api', // baseURL     
        credentials: true,
    },   
    proxy: {     
        '/api/': {       
            target: 'http://127.0.0.1:2001', // 代理地址       
            changeOrigin: true,       
            pathRewrite: {'^/api': ''},     
        },   
    } 
}

 

组件中使用

<script> 
    export default {   
        fetch ({ app }) {     
            console.log(app.$axios)   
        },   
        asyncData ({ app }) {     
            console.log(app.$axios)   
        },   
        created () {     
            console.log(this.$axios)   
        } 
    } 
</script>

 

到此为止,我们并不需要在plugins配置axios,但是如果要设置全局拦截器,那么就要新建一个/plugins/axios.js

export default function (app) {   
    let axios = app.$axios;   // 基本配置   
    axios.defaults.timeout = 10000 
    axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded'   // 请求回调   
    axios.onRequest(config => {})  // 返回回调                    
    axios.onResponse(res => {})   // 错误回调   
    axios.onError(error => {}) 
}

然后在plugins配置它

module.exports = {   
    plugins = [     
        {src: "~/plugins/axios",ssr: false},   
    ] 
}

 

9. 默认Meta标签

nuxt.config.js

module.exports = {   
    head: {     
        title: 'your project title',
        meta: [
           { charset: 'utf-8' },
           { name: 'viewport', content: 'width=device-width, initial-scale=1' }     
        ],
        link: [
        { rel: 'stylesheet', href: 'https://fonts.googleapis.com/css?family=Roboto' }
        ]
    } 
}

 

10. 页面组件特有的Meta标签

<script> 
    export default {   
        head () {     
            return {       
                meta: [         
                    {name: 'keywords', content: '最强王者,今晚吃鸡'},       
                ]     
            }   
        } 
    } 
</script>

 

11. 动态路由的Meta标签填充

游戏详情页面举例子,由于数据是异步获取的,我们需要把数据获取写在asyncData钩子,待数据获取成功才会渲染该页面组件

<script> 
    export default {   
        async asyncData ({ app, params }) {    
            let data = await app.$axios.get(`/appinfo/${params.id}`);
            return {       
                appname: data.appinfo.appname     
            }   
        },   
        head () {     
            return {       
                meta:[{           
                    name: 'keywords',           
                    content: `${this.appname},无限宝石,无限元宝`
                },]     
            }   
        } 
    } 
</script>

 

12. 使用Vuex

nuxt自己集成了vuex,所以不需要安装,在/store目录下新建index.js即可使用

import Vuex from 'vuex' 

let store = () => new Vuex.Store(
    {   state: {     token: ''   },   
    mutations: {     
        setToken (state, token) {        
            state.token = token     
        }   
    } 
}) 

export default store

 

13. 登录状态?

vue-cli项目中,我们可以用vuex-persistedstate,它可以使vuex的状态持久化,页面刷新都不会丢失,原理当然是localStorage啦!当然我更喜欢用vue-cookies进行保存token,问题来了,nuxt项目怎么保存登录状态呢?当然上面这两种方法我们都可以使用,但是有个问题,由于在created钩子中不存在window对象(获取cookie、localStorage都需要window对象),当你需要判断是否存在token的时候,你必须要在mounted进行操作,这说明页面进来的一瞬间你无法得知是否已经登录了,这会导致显示用户名、组件显示于隐藏都慢半拍

 

nuxt非常友好,它提供了fetch钩子,还有nuxtServerInit,这两个钩子都运行在服务端并且我们能很快速地操作store

14. fetch的使用

如果页面组件设置了fetch方法,它会在组件每次加载前被调用(在服务端或切换至目标路由之前),此方法需要跟服务端的人员配合

<script> 
    export default {   
        async fetch ({ app, store, params }) {     
            let { data } = app.$axios.get('/token');
            store.commit('setToken', data.token);   
        } 
    } 
</script>

 

15. nuxtServerInit

终极无敌方法

import Vuex from 'vuex' 

let store = () => new Vuex.Store({   
    state: {     token: ''   },   
    mutations: {     
        setToken (state, token) {        
            state.token = token     
        }   
    },   
    actions: {     
        nuxtServerInit({ commit }, { req }) {       
            let cookie = req.headers.cookie; // 将cookie转成json对象(自己实现该方法)       
            let token = cookieparse(cookie).token;
            commit('setToken', token);     
        },   
    } 
}) 

export default store

 

16. 封装属于自己的全局方法

let xielikang = function () {   
    /**    
    * @method 打印信息方法    
    * @param {String} msg 信息    
    */   
    let message = function (msg) {     
        msg && console.log(msg)   
    }   

    let otherfn = function (msg) {}   

    return {     message,     otherfn   } 
} 

Vue.prototype.$kang= xielikang

 

组件调用

<script> 
    export default {   
        created() {     
            this.$kang.message('小老弟,你怎么回事')   
        } 
    } 
</script>

对了,别忘了在plugins中配置,可以回到第7小节查看配置

 

17. 全局样式

nuxt.config.js

module.exports = {   css: ['~/assets/stylesheets/main.min.css'] }

 

18. 使用Element-UI

还是plugins文件夹新建element-ui.js

// 全局引入 
import Vue from 'vue' 
import ElementUI from 'element-ui' 

Vue.use(ElementUI) 

// 按需引入 
import { Button, Loading, MessageBox } from 'element-ui'

Vue.use(Button) 
Vue.prototype.$loading = Loading.service 
Vue.prototype.$msgbox = MessageBox

 

nuxt.config.js

module.exports = {   
    css: ['element-ui/lib/theme-chalk/index.css'],   
    plugins: [     
        {src: "~/plugins/element", ssr: true}   
    ] 
}

 

19. fetch、asyncData、validate使用范围

只能在页面组件使用,也就是pages目录下的组件,而不是components目录下的组件,要有所区分

 

20. 传统部署

npm run build && npm run start

 

21. pm2部署

它允许您永久保持应用程序活跃,无需停机即可重新加载它们,并不需要传统部署的.nuxt文件夹,该部署方法也跟生产环境一样含热更新

npm install pm2 -g 

npm run build pm2 start ./node_modules/nuxt/bin/nuxt-start