Nuxt 详细总结

1,407 阅读4分钟

- 生命周期

nuxt-lifecycle.svg

  • 只有初次访问返回的html是对应页面的实际DOM内容。之后在页面内进行跳转都是用内部vue-router方式。所以导致了只触发s端的asyncData函数
  • 加载serverMiddleware服务端相关的中间件
  • 加载服务端plugins及配置为{ model: 'server' }
  • 执行 store.action 内的nuxtServerInit 函数
  • 执行middleware全局/页面/路由中间件
  • 关于asyncData触发流程,服务器端的只执行一次
    • 初次访问连接时会执行s端的 asyncData 函数
    • 之后页面再跳转时执行的是c端的 asyncData 函数
    • 两者都会阻塞页面
  • 在服务端支持的vue生命周期只有beforeCreate/created
  • vuex会执行两次,但实际赋值是在serverInit阶段

- 于 VUE 不同点

  • <NuxtLink/NLink>代替<RouterLinke>
  • <Nuxt>代替<RouterView>
    • 嵌套路由的方式时父组件需要使用<NuxtChild>
    • 两者都接受keep-alive/keep-alive-props属性
  • <client-only>组件用于包裹只在c端显示的内容
  • vuex/router只提供相关配置内容,不需要手动挂载
  • pages目录结构要按照路由路径去更改,如果是使用params就需要修改名称为_.vue去适配

- 基础内容

  • context包含 app/store/route/params/query/env/isDev/isHMR/redirect/error/$config
    • redirect([status,] path [, query]) 重定向
  • nuxtjs 新增的page配置项
    • asynData 可获取ctx对象
      • 返回的内容将合并到data中,data 中不需要提前存在对应字段。并且会覆盖同名内容
      • 只能放在pages页面内,不能在组件/layout 中配置。并且会阻塞路由导航
      • 数据是挂载到window.__nuxt__全局变量上
    • fetch 也可获取ctx它是在实例创建后获取,所以能获取this对象
      • 所以执行周期也是在服务端created之后的
      • 页面内 fetch 是只在s端执行
      • 组件内 fetch 是在c端执行
    • head 可设置页面本身的meta属性
      • 就是封装的vue-meta组件
    • key 对一个就是<router-view>中的key属性
      • 可以配置在<Nuxt :nuxt-child-key="someKey" />
      • 也可以配置在页面内
    • layout 配置页面使用的特定全局布局
    • middleware 中间件,可以配置[ ...string ]或者是匿名函数
    • validate(ctx) 页面内的动态校验
      • 需要返回true/false。返回 Error/false 时将重定向到定义的error页面
        • 返回falseerror.statusCode = 404
        • 抛出异常时error.statusCode = 500
      • 注意:在页面内定义了validate函数后一定要有返回。不返回内容默认404
    • watchQuery 可配置[...string]和函数watchQuery(newQuery, oldQuery)
      • 监听的内容变化时,所有组件方法都将被重新调用。实测好像只触发validate/asyncData
    • 注意
      • validate/asyncData/fetch 等如果在s端触发过了,在c端就不再重复触发了
  • 约定式目录结构
    • middleware 模块
      • 需要返回一个函数,入参为ctx对象
      • 可以在配置文件router.middleware中配置路由级别的
      • 也可以在 page 内的middleware配置页面级别的
    • plugins 模块
      • 可简单的用vue.use()安装全局组件/函数/mixins/filters
      • 也可使用export default (ctx, inject) => { inject('name', callback) }这样就可以在实例上app/this.$name获取
      • 注意:
        • 其他 js 内想获取router/store对象只能通过封装成组件的方式。比如在单独axios内使用store
    • layouts 模块
      • default.vue类似App.vue页面。不支持asyncData但是支持fetch所以它应该是组件
      • 自定义** error **页面需在该目录下layouts/error.vue。路由未找到、js 异常都会跳到该页面
        • 页面内可访问到this.error = {statusCode, path, message}信息
    • components 模块
      • 不建议使用全局方式,使用plugins方式手动注入更加的可控
    • pages(router) 模块
      • 使用_作为params方式传参的定义。query方式不用改变
      • 无知路由匹配:如果 pages 目录根下定义了_.vue那未匹配的路由不会进error.vue页。但validate() => false和抛异常还是进error.vue
    • store 模块
      • 目录内每个.js默认都会被转为命名空间模块state使用函数方式定义
      • 可在store/index.js中配置nuxtServerInit(vuex, ctx)用于存储数据的填充。比在 asyncData 内填充更合适
      • 插件使用方式:需要在index.js内导出一个export const plugins = [xxx]
  • 其他内容
    • this.$nuxt内部对象
      • .refrest() 重新执行asyncData/fetch函数,是客户端模式
      • .$loading.start/finisht() 控制 nuxt 加载栏状态
      • .isOffline/.isOnline 检测连接
    • window.onNuxtReady( callback )回调只会在客户端执行

- nuxt.config.js 配置

  • 环境变量定义方式
    • process.server/client 用于区分环境。在c/s端都可获取
    • 配置.env.xxx文件并使用--dotenv读取的指令。所有的内容只在s端有效,通过process.env.xx获取
    • nuxt.config.js内配置的env: {}c/s端都可获取
      • 所以可以让env的配置从.env.xxx内获取
    • publicRuntimeConfig/privateRuntimeConfig运行时配置。privateRuntimeConfig不对浏览器开放
  • mode 定义模式spa/universal
  • serverMiddleware 服务端中间件。有点类似往const app = express/koa(); app.use();添加函数
    • (req, res, next) => {}内 req.path 只获取 request API 的地址
    • 内部使用connect组件库实现的 链接
  • loading 顶部进度条除了配置options,还可定义为一个xxx.vue的页面
  • loadingIndicator 用于在SPA模式下,在页面中展示一个 loading 效果
  • plugins 配置mode:client/server可控制插件执行的范围
  • router.base 用于配合 nignx 代理服务
    • 注意static目录访问需要改为~static/默认的/已经不生效
  • styleResources
    • @nuxtjs/style-resources 配合实现全局 css 注入
  • vue.config 可配置vue.config.js的配置项

- 高级用法 链接

  • 可以配合express/koa做更加灵活的事,把nuxt弄成服务端的中间件的形式继承进去。如果需求简单建议使用serverMiddleware方式
  • 相关 API 内容
    • 需要require('nuxt')导出{ loadNuxt, build }
      • loadNuxt 内部调用new Nuxt(config)并传入nuxt.config.js配置文件内容
      • 如果在nuxt.config.js内使用环境变量process.env.xxx记得需要先设置
    • nuxt.render 中间件服务
    • nuxt.renderRoute
    • 注意:使用前需要npm run build构建服务
// custom-server.js
const { loadNuxt } = require('nuxt');

// 模拟配置环境变量
process.env.NODE_ENV = 'production';
process.env.VUE_APP_ENV = 'prod';
process.env.VUE_APP_URL = '/actlp-nuxt/';
process.env.VUE_APP_API = '';
process.env.VUE_SERVER_API = '';

const app = require('express')();
const port = process.env.PORT || 3000;

async function start() {
  const nuxt = await loadNuxt('start');

  // 全局前置拦截
  app.use((req, res, next) => {
    console.log('---', req.path);
    next();
  });

  app.use(nuxt.render);

  app.listen(port, '0.0.0.0');
  console.log('Server listening on `localhost:' + port + '`.');
}

start();

- 部署系统

  • 提交.nuxt(可以自己定义)/static/nuxt.config.js/package.json等文件
  • 服务端执行npm i/npm run start然后配合nginx进行访问。或通过pm2执行npm run start命令
  • nginx 子目录代理配置方式
# actlp-nuxt
location ^~ /actlp-nuxt {
	# nuxt.config.js 内 router.base 也配置为 /actlp-nuxt/。
  # 实际项目运行在 localhost:3000/actlp-nuxt/ 下
	proxy_pass http://127.0.0.1:3001;
}

- 关于用户身份校验

  • 主要场景是在触发服务端asyncData函数时,内部调用 api 接口但需要关联用户身份信息
  • 如果是使用cookie方式的这就好解决了。request发送时会自动放到headers中,后端自然就可以获取
  • 但如果是jwt方式因为需要手动放到headers
    • 方式一:初次保存token时同时在storge/cookie都保存一份,这样cookie就走上面的方式
    • 方式二:直接使用nuxt-axios那也好处理可以配置拦截器。但是直接封装的axios由于没法拿到store所以只能把它移动到plugins目录下,使用插件的方式变相的获取store实例来处理