Nuxt3官方文档:https://nuxt.com/
Nuxt3中文文档:https://nuxt.com.cn/
模板目录结构文档:https://nuxt.com/docs/guide/directory-structure/nuxt
作者:时光
个人博客:https://timebk.cn/
版权声明:原创文章,请勿抄袭,思维有限,敬请指正,转载需注明作者和原文
安装
npx nuxi init <project-name>
- 1
- 安装的时候很大几率会遇到
Failed to download template from registry: fetch failed这个问题,中文直译过来就是无法从注册表下载模板:获取失败,放心,这不是你和你的网络问题!
网上的解决方法
1. 挂机场 // 实际无效
2. 修改本地网络DNS为114.114.114.114 // 实际无效
3. 在系统hosts文件里添加 raw.githubusercontent.com [该域名ip] // 实际无效
- 1
- 2
- 3
【重要】没错,上面的三种方法都基本无效!
最优的方法
访问以下链接:
- https://codeload.github.com/nuxt/starter/tar.gz/refs/heads/v3
- 即可直接下载模板,是最新的模板,而且不用挂梯子
- 下载好模板后,进行
npm i安装依赖,npm run dev进行项目开发,默认端口3000
初始模板里的 package.json
{
"private": true,
"scripts": {
"build": "nuxt build", // 打包
"dev": "nuxt dev", // 开发
"generate": "nuxt generate", // 静态生成
"preview": "nuxt preview", // 预览
"postinstall": "nuxt prepare" // 脚本处理
},
"devDependencies": {
"nuxt": "^3.3.1"
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
路由 > pages目录
Nuxt 是属于约定式的,在路由这方面很有新意
- 首先第一件事情就是删除
app.vue里的<NuxtWelcome />,这个是Nuxt官方的欢迎组件 - 然后在
app.vue里添加<NuxtPage :page-key="$route.fullPath" /> - 现在,我们只需要在根目录创建一个
pages文件夹 - 接着在
pages文件夹里新增一个.vue文件(名称的话你自己取,我这里为了方便教程就命名为about.vue),然后这个文件就已经进入路由了,你可以通过http://localhost:3000/about访问了


- 当然,
pages目录下的index.vue文件则是首页
嵌套路由
实际项目的需求咱们肯定不是只有 localhost:3000/about 这种一级路由,还会有 localhost:3000/about/1 、localhost:3000/about/1/1 这种嵌套路由
- 在Nxut3中,咱们要实现这种嵌套路由,是需要新建
同级相同名称目录的,以下我会继续以/about来作为讲解 - 比如我们现在有一个
/about页了,我们现在需要/about/1页面,那么我们就需要在同级文件夹新建一个about文件夹,再在这个文件夹里新建一个1.vue


- 我们现在来通过
useRouter().options.routes看一下routes的结构

- 这个结构是不是很熟悉?Nuxt3为我们自动生成了嵌套路由
- 更多级的路由你只需要套娃式地操作即可咯,注意,如果你不设置同级相同名称的目录和.vue文件,那么不会形成嵌套关系
布局 > layouts目录
这是Nuxt提供的一个可定制的公共布局框架
- 在项目根目录下创建一个
layouts文件夹

- 然后我们在
layouts文件夹下新建一个default.vue,它将作为<NuxtLayout />的默认布局


- 注意,这里的
<slot />是作为插槽出口,你需要有一定的Vue插槽概念基础:查看Vue官方插槽讲解 - 接着,在需要用到该布局的页面文件里添加
<NuxtLayout><NuxtLayout />即可

- 这里的
<slot />是作为插槽出口,你甚至可以定义name来区分插槽 - 你在
<NuxtLayout><NuxtLayout />里添加的元素将添加到布局文件里的slot插槽出口上

- 当然,你可以通过v-if条件编译区分公共布局是前台还是后台
- 如果我们需要为某个页面指定某个布局,我这里用
admin来作为演示,在layouts文件夹下新建一个admin.vue,然后在需要用到该布局的页面文件里添加<NuxtLayout name="admin" ><NuxtLayout />即可
中间件 > middleware目录
实际开发中,我们也许会在跳转某个路有前做点什么操作,或者说是决定是否跳转点击的路由
- 在项目根目录下创建
middleware文件夹 - 这个文件夹里面的文件是以
.js或者.ts(推荐)为格式的 - 你也可以叫他
导航守卫前
全局中间件
- 我们首先就需要定义一个全局的中间件,它的命名应该是
default.global.ts```
export default defineNuxtRouteMiddleware((to: any, from: any) => {
});
- 1
- 2
- 3
to和from是什么就不用多说了吧,就是获取上一个路由和下一个路由的路由信息,这个在Vue原生模板中我们必用的一个东西,不过注意这个中间件属于导航前- 然后你就可以根据业务需求编写代码了,它的一些语法请看官网学习,这里只是记录入门
扩展
在中间件里获取document、windows等
有的时候我们可能需要在这里获取Html元素,这时候我们不能直接获取到元素,比如document、windows等等因为是在服务端没有挂载前是不存在的


- 那么怎么解决呢
- 我们可以通过异步加载的方式获取


- 不过我是不推荐在中间件里操作document的,因为有的时候会出现莫名其妙的问题,比如我之前在这里面通过接口获取网站配置并保存到 Pinia 里,出现了服务器部署后访问项目强制刷新时无法获取到 Pinia 里的数据,所有还是推荐直接在
app.vue里进行类似操作
SEO优化和动态组合式Title
这个官网上有提,但是坑特别多,文档根本不完善,我这里记录一下我的方案
- 众所周知,网站是需要推广的,推广就需要较好的SEO,才能在搜索引擎上有较好的排名(当然你愿意花钱让别人帮你做词和提权重也不是不可以哈哈哈)
- 除了开发时注意标签语义化和尽量保证清晰的HTML结构,我们还需要在动态seo上面做努力~
- 下面以页面
tiitle作为例子哈! - 在
nuxt.config.ts文件里,我们可以通过配置app.head.title来设置全局的页面title

- 但是实际项目中我们肯定是需要每个页面都要有一个自己的title,而且可以组合base title的
- 我们需要这样做:
例子:近乎完美的SEO Title
- 先在
app.vue里添加useHead()配置

useHead({
titleTemplate: (productCategory) => {
const baseTitle = "时光小灶";
return `${productCategory ? productCategory + " - " : ""}${baseTitle}`;
},
});
- 1
- 2
- 3
- 4
- 5
- 6
- 然后,在我们的每个页面添加一个
<Title></Title>组件,标签里面的字符将作为当前页面的动态title

- 最终效果:

- 之后你部署到服务器和绑定域名后,通过第三方的seo查询均可以正常获取每个页面的title
Vue3 UI库 Element Plus
安装
npm i @element-plus/nuxt -D
- 1
// nuxt.config.ts
export default defineNuxtConfig({
modules: ["@element-plus/nuxt"],
elementPlus: {
/** Options */
},
});
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 安装好后就不需要手动import引入了
使用Icon 图标
- 在
elementPlus中添加icon: "ElIcon"
export default defineNuxtConfig({
modules: ["@element-plus/nuxt"],
elementPlus: {
/** Options *
icon: "ElIcon",
},
});
- 1
- 2
- 3
- 4
- 5
- 6
- 7
手动导入
- 现在,你可以通过
import { User, Lock } from "@element-plus/icons-vue";来使用所需要的图标 - 但是这种很麻烦,每一个图标都需要手动导入一下
自动导入
- 在
plugins文件夹里的global.ts文件里添加如下代码
import * as ElementPlusIconsVue from "@element-plus/icons-vue";
export default defineNuxtPlugin(async (NuxtApp) => {
// 其他code
// 全局组件引入
for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
NuxtApp.vueApp.component(key, component);
}
// 其他code
});
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
Pinia 及 持久化
安装
npm i pinia @pinia/nuxt
- 1
使用
- 在
项目名根目录创建stores文件夹 - 在
stores文件夹里创建一个.ts文件,文件名自己取,之后使用的时候正确路径导入即可,下面以adminInfo.ts作为示例
// adminInfo.ts
import { defineStore } from "pinia";
export const adminConfig = defineStore("adminConfig", {
state: () => {
return {
adminConfig: {},
};
},
actions: {
adminConfigSet(data = {}) {
this.adminConfig = data;
},
},
});
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 然后需要使用的页面导入即可
import { adminConfig } from "~/stores/adminConfig";
const store = reactive<any>(adminConfig().adminConfig);
- 1
- 2
- 更多的关于Pinia知识点请到官网学习:Pinia官网
持久化 pinia-plugin-persistedstate
安装
- 为了实现持久化,我们需要使用到一个依赖
@pinia-plugin-persistedstate/nuxt
npm i -D @pinia-plugin-persistedstate/nuxt
- 1
- 然后在
nuxt.config.ts里添加配置
export default defineNuxtConfig({
// other code
modules: ["@pinia/nuxt", "@pinia-plugin-persistedstate/nuxt"],
// other code
});
- 1
- 2
- 3
- 4
- 5
用法
- 创建 Store 时,将
persist选项设置为true
// adminInfo.ts
import { defineStore } from "pinia";
export const adminConfig = defineStore("adminConfig", {
state: () => {
return {
adminConfig: {},
};
},
actions: {
adminConfigSet(data = {}) {
this.adminConfig = data;
},
},
persist: true,// 设置为true
});
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
注意
- 默认情况下,Store 将被保存在 cookie 中(在底层使用 Nuxt 的 useCookie)
选择 storage
- 但可以通过使用自动导入的
persistedState变量下的可用 storage 来配置你想要使用的 storage
import { defineStore } from "pinia";
export const adminConfig = defineStore("adminConfig", {
state: () => {
return {
adminConfig: {},
};
},
actions: {
adminConfigSet(data = {}) {
this.adminConfig = data;
},
},
persist: {
// 下面的二选一
storage: persistedState.localStorage,// localStorage
storage: persistedState.sessionStorage,// sessionStorage
}
});
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19