zoukankan      html  css  js  c++  java
  • Nuxt开发经验分享

    Nuxt开发经验分享

    本文章基于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' }
        ]
      }
    }
    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部署

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

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



     
     
     
     
     

    参考:
    作者:daydreammoon
    链接:https://www.jianshu.com/p/840169ba92e6

    -------------------------------------------

    个性签名:独学而无友,则孤陋而寡闻。做一个灵魂有趣的人!

    如果觉得这篇文章对你有小小的帮助的话,记得在右下角点个“推荐”哦,博主在此感谢!

    万水千山总是情,打赏一分行不行,所以如果你心情还比较高兴,也是可以扫码打赏博主,哈哈哈(っ•̀ω•́)っ✎⁾⁾!

  • 相关阅读:
    .net core读取appsettings.config中文乱码问题
    vs2017错误:当前页面的脚本发生错误
    VS Code中无法识别npm命令
    Visual Studio报错/plugin.vs.js,行:1074,错误:缺少标识符、字符串或数字
    记录一次在生成数据库服务器上出现The timeout period elapsed prior to completion of the operation or the server is not responding.和Exception has been thrown by the target of an invocation的解决办法
    Java集合框架
    java hash表
    Java Dictionary 类存储键值
    java数据结构 栈stack
    java封装
  • 原文地址:https://www.cnblogs.com/mahmud/p/10292370.html
Copyright © 2011-2022 走看看