生命周期划分

nuxt搭建的vue框架的生命周期分三部分来看:nuxt的生命周期、vue的生命周期、其他的生命周期

  • nuxt生命周期在服务端,输出在服务端或浏览器端
  • vue的beforeCreated和created钩子运行在在服务端客户端,输出在服务端或浏览器端
  • vue的其他的生命周期在客户端,输出在浏览器端

nuxt生命周期 钩子

  • Nuxt的生命周期跑在服务端,但是他的输出即可能在服务端也可能在浏览器
  • Nuxt生命周期的钩子一般都会接受一个上下文参数context,里面包含着服务端的多种数据信息:{isDev, route, store, env, params, query, req, res, redirect, error }等

生命周期图:

在这里插入图片描述

nuxtServerInit

一个用于处理store数据的钩子,只会执行一次,一般用于操作store数据的初始化。
一般写在store文件夹中,运行在服务端,输出在服务端和客户端。

store/index.js:

export const actions = {
    /**
     * 
     * @param {*} store store的实例对象
     * @param {*} context 上下文(服务端所有的数据信息)
     */
    nuxtServerInit(store, context) {
        console.log("nuxtServerInit", store, context);
        
    }
}

服务端输出:
在这里插入图片描述
同时浏览器输出:


服务端和浏览器都有输出,说明输出可能在服务端也可能在浏览器,下面的几个Nuxt钩子有同样的状况。

middleware

中间件的钩子,可以自定义一些函数,可以运行在全局前,某个页面前,也可以运行在组件渲染前,需要在配置文件进行配置:

  • nuxt.config.js 全局中间件的配置
  • layouts 布局中间件的配置
  • pages 页面中间件的配置

执行顺序:全局中间件 ==> 布局中间件 ==>页面中间件
中间件都会有一个包含服务端上下文信息的参数context,可用可不用

  1. nuxt.config.js 全局中间件的配置
    这里以路由中间件为例:
    nuxt.config.js
export default {
  // 服务端渲染模式,同构
  mode: 'universal',
  /*
  ** 页面Head
  */
  head: {
    title: process.env.npm_package_name || '',
    meta: [
      { charset: 'utf-8' },
      { name: 'viewport', content: 'width=device-width, initial-scale=1' },
      { hid: 'description', name: 'description', content: process.env.npm_package_description || '' }
    ],
    link: [
      { rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' }
    ]
  },
  /**
   * 路由中间件配置
   */
  router: {
    middleware:'auth'
  },

  /*
  ** loading样式
  */
  loading: { color: '#fff' },
  /*
  ** 全局样式
  */
  css: [
  ],
  /*
  ** 全局插件
  */
  plugins: [
  ],
  /*
  ** 开发模式的模块
  */
  devModules: [
  ],
  /*
  ** 模块
  */
  modules: [
  ],
  /*
  ** 打包配置
  */
  build: {
    /*
    ** You can extend webpack config here
    */
    extend (config, ctx) {
    }
  }
}

文件的名字就是该中间件的名字:
middleware/auth.js:

/**
 * 接收一个全局上下文参数context
 */
export default ({ store, route, redirect, param, query, req, res }) => { 
    // 全局守卫业务
    console.log("router-middleware")
}

访问任何路径都会输出router-middleware

中间件的几个参数信息,这几个参数是存储在全局上下文参数context中的:

  • store: 状态树信息,vuex的相关信息
  • route:目标路由的信息
  • redirect:强制跳转
  • param:param参数信息
  • query:query参数信息
  • req:请求的req信息
  • res:响应的res信息
  1. layout 布局中间件的配置
    layouts/default.vue
<template>
  <div>
    <nuxt />
  </div>
</template>
<script>

export default {
  // layout层级中间件
  // 1. 引用外部中间件
  middleware: 'auth',
  // 2. 使用内部中间件
  middleware() {
    console.log('layout middleware')
  }
}
</script>
  1. page页面中间件的配置
    页面中间件运行在页面实例化之前

pages/index.vue

<template>
  <div class="container">
  </div>
</template>

<script>
import Logo from '~/components/Logo.vue'

export default {
  // 中间件
  // 1. 引用外部中间件
  middleware: 'auth',
  // 2. 使用内部中间件
  middleware() {
    console.log('page middleware')
  },
  components: {
    Logo
  },
}
</script>

validate

校验客户端请求所携带的参数是否符合校验,校验成功可以返回页面,否则返回404页面。
运行在请求发出后,页面初始化之前,所以一般在页面中使用validata钩子。

<template>
  <div class="container">
  </div>
</template>

<script>
import Logo from '~/components/Logo.vue'

export default {

  validate({ param, query }) {
    // 校验业务
    return true;//校验通过
  },
  components: {
    Logo
  },
}
</script>

asyncData & fetch

用于处理异步数据

  • asyncData :渲染组件前获取异步数据数据
  • fetch:也是在渲染组件前获取异步数据数据
    一般在页面中使用这两个钩子,在页面渲染之前获取数据。
    pages/index.vue
<template>
  <div class="container">
    <div>
      <logo />
      <h1 class="title">
        SSR2.9
      </h1>
    </div>
  </div>
</template>

<script>
import Logo from '~/components/Logo.vue'

export default {
  // 获取数据,返回给组件
  asyncData() {
    // 异步业务逻辑,读取服务端数据
    // 返回结果和组件的目标数据(data(){})进行合并
    console.log("asyncData");
    return {
      b:2
    }
  },
  // 获取数据,返回给状态数(vuex)
  fetch({store}){
    // 异步业务逻辑,读取服务端数据交给vuex
    console.log("asyncData");
  },
  components: {
    Logo
  },
  data() {
    return {
      a:1
    }
  }
}
</script>

Render

服务端渲染,将渲染后的页面返回给客户端。
不同页面间需要操作相同的数据请求的时候,只要数据发生变化,Render都会重新渲染。

  • render函数之定义渲染的配置,内部不要编写业务逻辑,即使写的也不执行

nuxt生命周期 和 vue生命周期钩子之间的运行顺序

nuxt生命周期钩子 ⇒ vue的beforeCreated和created钩子 ⇒ vue的其他生命周期钩子
在这里插入图片描述

钩子的参数信息

  • 在服务器端运行的钩子都可以拿到服务器端的上下文信息,但是拿不到客户端的数据(如windows),不能访问this.
    服务端的钩子运行客户端渲染前,自然拿不到客户端的数据信息
  • 在客户端运行的vue钩子都可以拿到客户端的数据(如windows),不能拿到服务器端的上下文信息,可以访问this,代表的是组件实例自身。
  • 既运行在服务端的钩子有运行在客户端的钩子(beforeCreate和create)可以拿到服务器端的上下文信息,但是拿不到客户端的数据(如windows),可以访问this,代表的是组件实例自身。

Nuxt SSR渲染的顺序

简单来说

服务端钩子子执行 ==> 服务渲染生成HTML(此时页面就已经可以展示给用户了,只是不能进行DOM操作) ==> 客户端钩子执行(Vue接管页面并进行客户端激活,为页面添加DOM操作)
可以查看VUE最原始的SSR实现进行理解:https://cn.vuejs.org/guide/scaling-up/ssr.html

具体来说

服务端渲染阶段:

  • nuxtServerInit(如果存在):在 Vuex store 中定义,用于在服务端初始化 store。
  • middleware(如果存在):在进入页面之前调用,用于中间件逻辑。
  • validate(如果存在):在进入页面之前调用,用于验证路由参数。
  • asyncData(如果存在):在组件实例化之前调用,用于异步获取数据。
  • fetch(如果存在):在组件实例化之前调用,用于获取数据。
  • serverPrefetch(如果存在):在组件实例化之前调用,用于在服务端预取数据。
  • 服务端渲染组件树并生成 HTML。
  • 将渲染好的 HTML 发送到客户端。

客户端激活阶段:

  • 客户端接管并激活 Vue 组件。
  • 执行客户端钩子函数(beforeCreate 和 created 会在服务端和客户端都执行)。
  • beforeMount:在组件挂载到 DOM 之前调用。
  • mounted:在组件挂载到 DOM 之后调用。

Fetch和mounted的执行顺序

  • 正常情况下的执行顺序是: Fetch(服务端执行,执行完才会生成HTML) ==> HTML ==> mounted(客户端执行),这种情况下可以确保mounted钩子是在Fetch钩子执行完之后才执行的。
  • 有特殊性情况:当组件不是在页面初始渲染的时候就已经存在,那么SSR渲染的时候并不会执行该组件中的fetch函数,而是在客户端激活阶段或在组件实际渲染到页面时执行。那么执行顺序就是 HTML ==>Fetch(客户端执行) ==> mounted(客户端执行),执行顺序是fetch先执行mounted后执行,但是钩子函数是到什么时间节点触发什么钩子,所以mounted是不会等fetch执行完再执行。
    具体参见:https://blog.csdn.net/mantou_riji/article/details/140550360
Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐