美文网首页让前端飞SEO前后端分离javascript Vue uni-app
Nuxt开发经验分享,让你踩少点坑!

Nuxt开发经验分享,让你踩少点坑!

作者: 聪明的汤姆 | 来源:发表于2018-09-18 17:27 被阅读21次

    说明

    本文章基于starter-template模板进行讲解,面向有vue-cli开发经验的宝宝

    vue init nuxt-community/starter-template
    

    Nuxt

    官方文档

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

    生命周期

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


    生命周期流程图,红框内的是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 lang="html">
      <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
        }
      ]
    }
    

    18. 如何使用sass预处理器

    安装依赖

    npm install node-sass sass-loader --save
    

    组件中使用(不需要其他的配置了)

    <style lang="scss" scoped>
    
    </style>
    

    19. fetch、asyncData、validate使用范围

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

    20. 部署

    npm run build && npm run start
    

    21. pm2部署

    它允许您永久保持应用程序活跃,无需停机即可重新加载它们

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

    本文到此就结束啦,这是目前踩的坑,如果有错误的地方,请大家指出

    相关文章

      网友评论

        本文标题:Nuxt开发经验分享,让你踩少点坑!

        本文链接:https://www.haomeiwen.com/subject/godynftx.html