nuxt.config.ts的配置
1. 配置应用标题和图标
export default ({
app: {
head: {
title: '我是nuxt应用', // 应用的默认标题
charset: "utf-8", // 字符集
htmlAttrs: {
lang: "zh-CN", // HTML的语言属性为“zh-CN”(中文)
},
// 修改页签图标
link: [
{
rel: 'icon',
type: 'image/x-icon',
href: '/favicon.png', // 该图片文件的放置在根目录下的public下
},
],
},
},
...
});
应用的头部配置需要放置在app:{}中,
2. 配置渲染方式
服务端渲染
export default ({
ssr: true
...
});
客户端渲染
export default ({
ssr: false
...
});
混合渲染
export default ({
// ssr: false 这里可以不用写
routeRules: {
'/': { ssr: true }, // 开启服务端渲染
'/route1': { ssr: false }, // 仅客户端渲染
'/route2': { ssr: false }, // 仅客户端渲染
'/route1/*': { ssr: false },// 仅客户端渲染
'/route2/*': { ssr: false },// 仅客户端渲染
},
...
});
3. 配置端口
export default ({
devServer: {
port: 8080, //配置端口为8080
},
server: {
port: 3000,
host: '0.0.0.0', //指定应用在生产环境中可被访问的主机地址。设置为 '0.0.0.0' 表示应用将接受来自任何 IP 地址的请求。
timing: false, //用于启用或禁用服务器端请求计时,这对于调试和性能监控可能有用。
},
...
});
server 配置是针对生产环境的,而 devServer 配置是针对开发环境的。
4. 配置开发代理--网关配置
nuxt3的代理需要在nitro里面进行配置
export default ({
nitro: {
devProxy: {
"/api": {
target: "http://xxx.xxx.x.xxx:xxxx", // 后端的接口地址
changeOrigin: true,
prependPath: true,
},
},
routeRules: {
'/api/**': {
proxy: 'http://xxx.xxx.x.xxx:xxxx/**'
}
}
},
...
});
注意routeRules后面还有/**,这是必不可少的,devProxy 是客户端渲染的,而 routeRules 是针对的服务端渲染的。
5. 多环境开发配置
假设我们有多个环境,如dev、sit环境,这里采用的是通过命令行传参,定义构建的是哪个环境,并在项目里接收参数设置环境变量。
在根目录下新建一个文件,这里叫作build.js,进行参数的接收
// build.js
// 解析命令行参数
//这里是获取构建命令 --env=环境,注意,我们通过process.env.npm_config_argv获取的对象是字符串的形式,所以需要通过JSON.parse进行转换
const envArg = JSON.parse(process.env.npm_config_argv)?.original[1];
//sit
const env = envArg ? envArg.split('=')[1] : 'dev'; //
// 设置环境变量
process.env.NUXT_ENV_MODE = env;
// 接下来,调用 Nuxt 构建命令或其他需要的脚本
console.log(`正在以 ${env} 模式构建...`);
在nuxt.config.ts文件引用,并且修改nitro routeRules的proxy
import './build.js';
...
function getEnv(env: any) {
let api = '';
switch (env) {
case 'dev':
api = 'http://dev-api/**';
break;
case sit:
api = 'http://sit-api/**';
break;
}
return api;
}
...
export default ({
nitro: {
routeRules: {
'/api/**': {
proxy: getEnv(process.env.NUXT_ENV_MODE)
}
}
},
...
});
规定构建命令传参方式(“--env=环境变量”是我们的参数):
//构建命令 终端执行
yarn build --env=环境变量
//例子——构建sit环境
yarn build --env=sit
这时候执行构建命令,便可以构建出相应的环境了
更多关于nuxt.config.ts的配置可参考:ezdoc.cn/docs/nuxtjs…
插件的安装并全局引入
ant-design-vue
除了使用yarn或npm等命令安装ant-design之外,需要在根目录创建一个plugins文件夹(有就不用创建了)创建一个文件(这里用的是ts)antd.ts
// plugins/antd.ts
import Antd from 'ant-design-vue';
import 'ant-design-vue/dist/antd.less';
import { defineNuxtPlugin } from 'nuxt/app';
export default defineNuxtPlugin((nuxtApp) => {
nuxtApp.vueApp.use(Antd);
});
nuxt.config.ts配置
export default ({
plugins: [
'@/plugins/antd.ts',
'@/plugins/echarts.ts',
{ src: '@/plugins/pdf.ts', ssr: false, mode: client }
],
...
});
类似这样的依赖库需要在plugins文件夹下创建文件全局引入,并在nuxt.config.ts,但类似less、typescript等插件或扩展类的直接使用命令安装相应的版本就可以了。
接口的封装
在nuxt中,我们可以使用useAsyncData或useFetch进行接口的调用,在这里我采用了二者的接口,使用useFetch进行接口的调用,useAsyncData对useFetch获取的数据进行处理。
1. useFetch的封装
import { type UseFetchOptions } from "nuxt/app";
export interface IResultData {
data?: any;
code?: number;
message?: string;
success?: boolean;
}
// 封装请求函数
async function request(
url: string,
option?: UseFetchOptions<IResultData>,
): Promise<Partial<IResultData>> {
if (process.client) {
await nextTick(); //解决刷新页面useFetch无返回
}
const { data } = await useFetch<IResultData>(url, {
onRequest({ options }) {
// 设置请求头
options.headers = {....};
return options;
},
// 请求拦截error
onRequestError({ response }) {
throw new Error(response);
},
// 响应拦截
onResponse({ response }) {
const { code, message } = response._data;
if (code !== SUCCESS_CODE) {
throw new Error(message);
}
return response._data;
},
...option
}
);
return data.value || {};
}
// 封装常用方法
export function get(url: string, params?: any, options?: UseFetchOptions<IResultData>) {
return request(url, { method: "GET", params, ...options });
}
export function post(url: string, params: any, options?: UseFetchOptions<IResultData>) {
return request(url, { method: "POST", body: params, ...options });
}
export function put(url: string, params: any, options?: UseFetchOptions<IResultData>) {
return request(url, { method: "PUT", body: params, ...options });
}
export function del(url: string, params: any, options?: UseFetchOptions<IResultData>) {
return request(url, { method: "DELETE", body: params, ...options });
}
2. useAsyncData的使用
useAsyncData('get-data', async () => {
const results = await Promise.allSettled([api1(), api1()]);
results?.forEach((result, index) => {
if (result.status === 'fulfilled') {
switch (index) {
case 0:
const data1 = result.value.data;
break;
case 1:
const data2 = result.value.data;
break;
}
} else {
console.error(`Request ${index} failed:`, result.reason);
}
});
});
当需要执行并行和独立的异步操作并收集所有结果时,Promise.allSettled() 就是不错的选择,即使一些异步操作可能失败。
如果不需要执行多个接口:
useAsyncData('get-data-2', async () => {
const res = await api()
console.log(res)
});
注意:如果在同一个页面中使用useAsyncData执行多个相同的接口(但参数不一样)会导致最终的数据都会被最后调用的那个接口的数据覆盖。解决办法,不使用useAsyncData执行,采用常见的项目的接口调用方法。
路由生成
nuxt的项目会对在pages目录下的文件自动生成路由,不需要自行配置,除components文件夹外;components文件夹下的文件不会被nuxt处理。
Nuxt.js 依据 pages 目录结构自动生成 vue-router 模块的路由配置。假设 pages 的目录结构如下:
pages/
--| custompage/
-----| index.vue
--| index.vue
那么,Nuxt.js 自动生成的路由配置如下:
router: {
routes: [
{
name: 'index',
path: '/',
component: 'pages/index.vue'
},
{
name: 'custompage',
path: '/custompage',
component: 'pages/custompage/index.vue'
}
]
}
layout布局
在根目录下的layouts文件夹下的存储的是页面的布局,命名为default的文件会成为每一个页面级的默认布局。例子:
<template>
<CHeader />
<div>
<slot></slot>
</div>
<CFooter />
</template>
<script lang="ts">
import CHeader from '@/components/common/CHeader.vue';
import CFooter from '@/components/common/CFooter.vue';
export default defineComponent({
name: 'layout',
components: { CHeader, CFooter},
});
</script>
在app.vue使用
<template>
<div id="app">
<NuxtLayout>
<NuxtPage></NuxtPage>
</NuxtLayout>
</div>
</template>
如果某个页面不需要使用这个布局
<script lang="ts">
export default defineComponent({
name: 'xxxx',
setup() {
//ui布局
definePageMeta({
layout: false,
});
},
});
</script>
使用其他布局则把layouts文件夹下的文件名赋值给definePageMeta的的layout属性就好:
<script lang="ts">
export default defineComponent({
name: 'xxxx',
setup() {
//ui布局
definePageMeta({
layout: '其他布局的文件名',
});
},
});
</script>
编码常见
1. <ClientOnly>标签
在服务端渲染的页面中,如果存在部分组件需要进行客户端渲染可使用该标签进行包裹,如:
<ClientOnly>
<我是客户端渲染的组件/>
</ClientOnly>
2. 只能在客户端渲染代码
在Nuxt 3中,有些行为或代码只适用于客户端(浏览器环境),在服务端渲染(SSR)环境中执行时会报错。这通常是因为某些对象或功能在Node.js环境中不存在,但在浏览器中是可用的。以下是一些在服务端渲染中可能导致错误的常见情况:
- 访问浏览器特定的全局对象:例如
window、document、localStorage和sessionStorage。这些对象只在浏览器环境中存在,在服务端渲染中使用它们会导致ReferenceError。 - 直接操作DOM:任何直接操作DOM的代码,如
document.getElementById或使用querySelector,在服务端都会失败,因为在Node.js环境中没有DOM。 - 依赖于浏览器API的功能:例如
FileReader、WebSocket、CanvasAPI,这些只在浏览器中定义。 - 客户端特定的事件处理:比如监听滚动事件、点击事件等。这些在服务端没有相应的环境来触发它们。
- 使用浏览器导航和位置接口:如使用
window.location或historyAPI来处理URL和导航。
如果需要进行上述行为,我们可以采取以下措施
- 使用
process.client和process.server来判断当前代码是在客户端还是服务端执行,并据此调整行为。 - 将依赖于客户端API的代码放在Vue的生命周期钩子
mounted中,因为mounted只在客户端调用。 - 对于客户端专用的功能或组件,可以使用动态导入(dynamic import)并结合
ssr: false来避免在服务端加载它们。 - 使用<ClientOnly>标签对使用上述代码的组件进行包裹。