Nuxt3-04插件和中间件

1,154 阅读1分钟

自动导入

在nuxt3中约定大于配置,nuxt3的hook函数、vue3的api以及约定的目录无需单独引入

约定的目录

  • 目录components下的组件
  • 目录composables的组合函数
  • 目录middleware下的前端中间件
  • 目录pages下的页面
  • 目录plugins下的插件

plugins

该目录下的js、ts文件会被注册成插件,插件的功能比较强大,可以获取vue实例、可以注册中间件等

  • xxx.ts默认在客户端和服务端都生效
  • xxx.client.ts在客户端生效的插件
  • xxx.server.ts在服务端生效的插件

基础使用

//plugins/hello.js
export default defineNuxtPlugin(() => {
  return {
    provide: {
      hello: (msg: string) => `Hello ${msg}!`
    }
  }
})
//pages/index.vue
<template>
  <div>
    {{ $hello('world') }}
  </div>
</template>

<script setup lang="ts">
// alternatively, you can also use it here
const { $hello } = useNuxtApp()
</script>

安装element-plus

yarn add element-plus

// plugins/element-plus.js
// 注意element-plus.js并没有添加.client 后缀,因为我们希望在服务端也可以预渲染element组件。但是某些element组件会报错,需要用<ClientOnly>处理一下

import ElementPlus, { ID_INJECTION_KEY } from 'element-plus'
import 'element-plus/dist/index.css'
import zhCn from 'element-plus/dist/locale/zh-cn.mjs'
export default defineNuxtPlugin((nuxtApp) => {
  nuxtApp.vueApp
    .use(ElementPlus, {
      locale: zhCn,
    })
    .provide(ID_INJECTION_KEY, {
      prefix: 100,
      current: 0,
    })
})

//<ClientOnly>
<ClientOnly>
<el-row :gutter="50">
  <el-col :span="4">
    <el-select
      v-model="form.status"
      size="large"
      placeholder="任务状态"
      style="width: 100%"
      clearable
      @change="fetchOrdersThirdHandle"
    >
      <el-option
        v-for="(item, index) in optionsMall"
        :key="index"
        :label="item.label"
        :value="item.value"
      />
    </el-select>
  </el-col>
</el-row>
</ClientOnly>

解决document is not definided,  window is not definided

有时候我们使用的第三方库需要依赖window环境,也可以使用插件的方式处理

以腾讯的cos为例

// utils/cos.js

import COS from 'cos-js-sdk-v5'
// 在组件中直接使用会报 window is not definided

async function cos(cosConfig) {
  return {
    // 实例化
    cosInstance: new COS({
      async getAuthorization(options, callback) {
        callback({
          TmpSecretId: cosConfig.credentials.tmpSecretId,
          TmpSecretKey: cosConfig.credentials.tmpSecretKey,
          SecurityToken: cosConfig.credentials.sessionToken,
          // 建议返回服务器时间作为签名的开始时间,避免用户浏览器本地时间偏差过大导致签名错误
          StartTime: cosConfig.startTime, // 时间戳,单位秒,如:1580000000
          ExpiredTime: cosConfig.expiredTime, // 时间戳,单位秒,如:1580000000
        })
      },
    }),

    // 上传
    async uploadFile(params, callback, opts: any = {}) {
      const key = cosConfig.keyPrefix + params.file.name
      this.cosInstance.uploadFile(
        {
          Bucket: cosConfig.bucket /* 填写自己的bucket,必须字段 */,
          Region: cosConfig.region /* 存储桶所在地域,必须字段 */,
          Key: key /* 存储在桶里的对象键(例如:1.jpg,a/b/test.txt,图片.jpg)支持中文,必须字段 */,
          Body: params.file, // 上传文件对象
          SliceSize:
            1024 *
            1024 *
            5 /* 触发分块上传的阈值,超过5MB使用分块上传,小于5MB使用简单上传。可自行设置,非必须 */,
          onTaskReady: function (taskId) {
            /* 非必须 */
            // console.log(taskId)
          },
          onProgress: function (progressData) {
            // console.log(JSON.stringify(progressData))
            opts.onProgress(progressData)
          },
        },
        callback
      )
    },
  }
}

export default cos
// plugins/cos.client.ts
import cos from '~/utils/cos'

export default defineNuxtPlugin(() => {
  return {
    provide: {
      cos,
    },
  }
})
// 使用
const {$cos} = useNuxtApp()

middleware

相当于vue-router中的router.beforeEach钩子。可以在路由跳转之前进行拦截,适合鉴权和守卫路由。有三种使用方式 此目录下的中间件仅在vue端运行,区别于server/middleware(属于服务端nitro的中间件)

方式一:页面内联

<script setup>
definePageMeta({
  middleware: (to) => {
    console.log('page middleware')
    return navigateTo('/home')
  },
})
</script>

方式二:middleware目录下新建auth.js

// middleware/auth.js

export default defineNuxtRouteMiddleware((to, from) => {
    console.log('middleware-auth')
})

// 页面中使用
definePageMeta({
  middleware: ["auth"]
  // or middleware: 'auth'
})

方式三:middleware目录下新建auth.global.js

  • 带.global的钩子会在所有路由之前触发
// middleware/auth.global.js
export default defineNuxtRouteMiddleware((to, from) => {
    console.log('middleware-global-auth')
})

plugin动态添加中间件


export default defineNuxtPlugin(() => {
    // 全局中间件
    addRouteMiddleware(
        'plugin-global-auth',
        () => {
                console.log('plugin-middleware-global-auth')
        },
        { global: true }
    )
    
    addRouteMiddleware('plugin-auth', () => {
        console.log('plugin-middleware-auth')
    })
})

执行顺序

项目中存在多个中间件的执行顺序:

  • middleware/xxx.global.js > plugin动态添加的全局中间件 > 页面局部中间件
  • 页面局部中间件则和中间件的添加顺序有关

image.png