自动导入
在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动态添加的全局中间件 > 页面局部中间件
- 页面局部中间件则和中间件的添加顺序有关