各位观众,晚上好! 今天咱们来聊聊 Nuxt.js 里的“中间件 (Middleware)”这玩意儿。 别一听“中间件”就觉得高深莫测,其实它就像咱们生活中的保安,负责检查进出小区的每个人,确保安全和秩序。 在 Nuxt.js 里,中间件负责在页面渲染前后执行一些逻辑,比如权限验证、数据预取等等。 好了,废话不多说,咱们直接进入正题。
一、 什么是Nuxt.js中间件?
简单来说,Nuxt.js 中间件就是你在路由导航发生时,可以在特定时机执行的一段代码。 它们可以用于:
- 权限验证: 检查用户是否登录,是否有权限访问某个页面。
- 数据预取: 在页面渲染前,从 API 获取数据。
- 日志记录: 记录用户的访问行为。
- 重定向: 根据特定条件,将用户重定向到其他页面。
- 修改上下文: 修改
context
对象,向组件传递额外的信息。
二、 中间件的种类和定义方式
Nuxt.js 提供了几种定义中间件的方式:
- 路由中间件 (Route Middleware): 只能用于特定的路由。
- 命名中间件 (Named Middleware): 可以在
nuxt.config.js
中定义,并在组件中或路由配置中使用。 - 全局中间件 (Global Middleware): 应用于整个应用的每个路由。
让我们用代码来演示一下:
1. 路由中间件 (Route Middleware):
这种中间件直接在 pages
目录下的页面组件中定义。
// pages/secret.vue
<template>
<h1>Secret Page</h1>
</template>
<script>
export default {
middleware: 'auth', // 使用名为 'auth' 的中间件
async mounted() {
console.log('秘密页面挂载了!');
}
}
</script>
上面这段代码中,middleware: 'auth'
表示当前页面使用了名为 auth
的中间件。 但是,这个 auth
中间件是从哪里来的呢? 别急,咱们稍后会讲到。
2. 命名中间件 (Named Middleware):
这种中间件需要在 middleware
目录中定义,文件名就是中间件的名字。
// middleware/auth.js
export default function ({ store, redirect }) {
// 如果用户未登录
if (!store.state.auth.loggedIn) {
return redirect('/login')
}
}
在这个例子中,我们定义了一个名为 auth
的中间件。它检查用户是否登录,如果未登录,则重定向到 /login
页面。
现在,回到 pages/secret.vue
页面,它就可以使用这个 auth
中间件了。
3. 全局中间件 (Global Middleware):
全局中间件需要在 nuxt.config.js
中配置。
// nuxt.config.js
export default {
middleware: ['global-middleware'], // 注册全局中间件
plugins: [],
}
然后,在 middleware
目录下创建一个 global-middleware.js
文件:
// middleware/global-middleware.js
export default function ({ route }) {
console.log('全局中间件:当前路由是', route.path)
}
这个全局中间件会在每次路由改变时执行,并打印当前路由的路径。 需要注意的是,全局中间件的执行顺序取决于它们在 nuxt.config.js
中的注册顺序。
三、 中间件的执行顺序
中间件的执行顺序非常重要,它决定了你的应用程序的行为。 Nuxt.js 中间件的执行顺序如下:
nuxt.config.js
中配置的 全局中间件,按照它们在数组中的顺序执行。- 匹配路由的 布局中间件(如果存在)。
- 匹配路由的 页面中间件。
可以用一个表格来总结一下:
类型 | 位置 | 执行时机 | 顺序 |
---|---|---|---|
全局中间件 | nuxt.config.js |
每个路由 | 按照在 nuxt.config.js 中的声明顺序 |
布局中间件 | 布局组件 (layouts/default.vue ) |
匹配布局的每个路由 | 在页面中间件之前 |
页面中间件 | 页面组件 (pages/index.vue ) |
匹配页面的每个路由 | 在布局中间件之后 |
举个栗子:
假设我们有以下配置:
-
nuxt.config.js
:export default { middleware: ['global1', 'global2'], }
-
middleware/global1.js
:export default function ({ route }) { console.log('全局中间件 1', route.path); }
-
middleware/global2.js
:export default function ({ route }) { console.log('全局中间件 2', route.path); }
-
layouts/default.vue
:<template> <div> <nuxt/> </div> </template> <script> export default { middleware: 'layoutMiddleware', } </script>
-
middleware/layoutMiddleware.js
:export default function ({ route }) { console.log('布局中间件', route.path); }
-
pages/index.vue
:<template> <h1>Index Page</h1> </template> <script> export default { middleware: 'pageMiddleware', } </script>
-
middleware/pageMiddleware.js
:export default function ({ route }) { console.log('页面中间件', route.path); }
当用户访问 /
页面时,控制台的输出顺序将是:
全局中间件 1 /
全局中间件 2 /
布局中间件 /
页面中间件 /
四、 中间件的作用域
中间件的作用域指的是中间件可以访问哪些变量和函数。 Nuxt.js 中间件可以访问一个 context
对象,它包含了以下属性:
store
: Vuex store 实例。route
: 当前路由对象。params
: 路由参数。query
: 查询参数。req
: Node.js 请求对象 (仅在服务器端可用)。res
: Node.js 响应对象 (仅在服务器端可用)。redirect
: 用于重定向的函数。error
: 用于显示错误页面的函数。app
: Vue 应用程序实例。$axios
: Axios 实例 (如果使用了@nuxtjs/axios
模块)。env
: 环境变量 (nuxt.config.js 中定义的env
属性)。isDev
: 指示是否处于开发模式。isHMR
: 指示是否启用了热模块替换 (HMR)。payload
: 用于在服务器端和客户端之间传递数据的对象。
通过 context
对象,中间件可以访问应用程序的各个方面,并执行各种操作。
五、 服务器端和客户端导航的区别
Nuxt.js 是一个通用框架,这意味着它可以在服务器端和客户端运行。 中间件的执行行为在服务器端和客户端略有不同:
-
服务器端: 中间件在服务器端执行,用于预取数据、验证权限等。 在服务器端执行的中间件可以访问
req
和res
对象,这意味着它们可以读取请求头、设置响应头等。 服务器端执行的中间件对于 SEO 和首屏加载速度至关重要。 -
客户端: 中间件在客户端执行,用于处理路由切换、更新 UI 等。 在客户端执行的中间件可以访问
window
对象,这意味着它们可以操作 DOM、使用浏览器 API 等。
重要提示:
- 服务器端中间件 只能在服务器端运行,不能访问
window
、document
等浏览器对象。 - 客户端中间件 可以在客户端运行,但不能直接访问
req
和res
对象。
为了更好地理解服务器端和客户端导航的区别,咱们来看一个例子:
// middleware/server-client.js
export default function ({ route, req, res }) {
if (process.server) {
console.log('服务器端:', route.path, req.headers['user-agent']);
}
if (process.client) {
console.log('客户端:', route.path, window.innerWidth);
}
}
这个中间件在服务器端打印路由路径和 User-Agent,在客户端打印路由路径和窗口宽度。
六、 实际应用场景
让我们看一些实际应用场景,来巩固我们对中间件的理解。
1. 权限验证:
// middleware/auth.js
export default function ({ store, redirect, route }) {
const isAuthenticated = store.state.auth.loggedIn;
const requiresAuth = route.meta.requiresAuth !== false; // 默认需要登录
if (requiresAuth && !isAuthenticated) {
return redirect('/login?redirect=' + route.path);
}
}
// pages/profile.vue
<template>
<h1>Profile Page</h1>
</template>
<script>
export default {
middleware: 'auth',
meta: { requiresAuth: true } // 明确声明需要登录
}
</script>
在这个例子中,auth
中间件检查用户是否登录。 如果用户未登录,并且页面需要登录才能访问 (通过 route.meta.requiresAuth
属性判断),则重定向到 /login
页面,并将当前页面作为 redirect
参数传递。
2. 数据预取:
// middleware/fetch-data.js
export default async function ({ store, params }) {
if (!store.state.post) {
await store.dispatch('fetchPost', params.id);
}
}
// pages/posts/_id.vue
<template>
<h1>{{ post.title }}</h1>
<p>{{ post.content }}</p>
</template>
<script>
export default {
middleware: 'fetch-data',
computed: {
post() {
return this.$store.state.post;
}
}
}
</script>
// store/index.js
export const actions = {
async fetchPost({ commit }, id) {
const response = await this.$axios.$get(`/api/posts/${id}`);
commit('setPost', response);
}
};
export const mutations = {
setPost(state, post) {
state.post = post;
}
};
export const state = () => ({
post: null
});
在这个例子中,fetch-data
中间件在页面渲染前,从 API 获取文章数据,并将其存储到 Vuex store 中。 这样可以避免页面加载后再次发起请求,提高性能。
3. 重定向:
// middleware/redirect-mobile.js
export default function ({ redirect, req }) {
if (process.server) {
const userAgent = req.headers['user-agent'];
const isMobile = /Mobile|iP(hone|ad|od)|Android/i.test(userAgent);
if (isMobile) {
return redirect('/mobile');
}
}
}
// nuxt.config.js
export default {
middleware: ['redirect-mobile'],
}
这个全局中间件检测用户是否使用移动设备访问,如果是,则重定向到 /mobile
页面。 注意,这个中间件只在服务器端执行,因为我们需要访问 req
对象来获取 User-Agent。
七、 总结
Nuxt.js 中间件是一个强大的工具,可以让你在路由导航发生时执行各种操作。 掌握中间件的种类、执行顺序和作用域,可以帮助你构建更灵活、更高效的 Nuxt.js 应用程序。
希望今天的讲座对大家有所帮助! 如果大家还有什么问题,欢迎随时提问。
最后,别忘了多写代码,多实践,才能真正掌握 Nuxt.js 中间件的精髓! 祝大家编程愉快!