# Nuxt 3的笔记

Nuxt3中文官网 (opens new window)

转载于【技术胖】Nuxt3从零到实战手把手 免费视频图文教程 (opens new window)

# 简介

Nuxt3是基于Vue3发布的SSR框架,也是Vue全家桶系列的一员。

# 安装

创建Nuxt项目

npx nuxi init <project-name>
1

npx是npm新增的命令,上述命令相当于

# 第一步
npm i nuxi
# 第二步
nuxi init <project-name>
1
2
3
4

假若安装失败,可到https://github.com/nuxt/starter/tree/v3下载压缩包。

启动

# 安装依赖
npm install 或者 yarn install
npm run dev 或者 yarn dev
1
2
3

# 目录结构

- .nuxt               // 自动生成的目录,用于展示结果
- node_modules        // 项目依赖包存放目录
- .gitignore          // Git的配置目录,比如一些文件不用Git管理就可以在这个文件中配置
- app.vue             // 项目入口文件,你可以在这里配置路由的出口
- nuxt.config.ts      // nuxt项目的配置文件 ,这个里边可以配置Nuxt项目的方法面面
- package-lock.json   // 锁定安装时包的版本,以保证其他人在 npm install时和你保持一致
- package.json        // 包的配置文件和项目的启动调式命令配置
- README.md           // 项目的说明文件
- tsconfig.json       // TypeScript的配置文件
1
2
3
4
5
6
7
8
9

随着我们的开发目录也会越来越多,比如常用的还有下面三个目录。

- pages               // 开发的页面目录
- components          // 组件目录
- assets              // 静态资源目录
- layouts             // 项目布局目录
1
2
3
4

# 编写Hello World程序

通过上面的学习,我们知道了App.vue 这个文件是项目的入口文件。用VSCode打开文件,可以看到文件的基础结构。

<template>
  <div>
    <NuxtWelcome />
  </div>
</template>
1
2
3
4
5

其中<NuxtWelcom /> 就是一个框架自带的组件,我们直接删除就可以,不用纠结删除这个组件。删除后,在 \components 目录下新建一个文件,叫做HelloWorld.vue 然后编写下面的代码。

<template>
  <div class="">
    <h1>Hello World</h1>
  </div>
</template>

<script setup>
import {} from "vue";
</script>

<style scoped></style>
1
2
3
4
5
6
7
8
9
10
11

然后再回到app.vue文件中直接写入这个 HelloWorld组件.

<template>
  <div>
    <hello-world />
  </div>
</template>
1
2
3
4
5

打开VSCode的内置终端,然后输入 npm run devyarn dev 就可以启动调试服务了。 打开浏览器,在地址栏输入http://localhost:3000/ (opens new window) 就可以看到 HelloWord效果了。

# 页面和约定路由的使用

Nuxt3的一个特点就是约定式开发,讲究的是约定大于配置。这种开发形式就是按照框架的约定进行开发。我们按照框架约定新建一个pages 的文件夹,然后新建一个文件Demo1.vue 。注意,上面这两个步骤,就是约定开发,你必须这么作,否则框架就不认为你是一个页面。

<template>
  <div class=""><h1>Demo01</h1></div>
</template>
1
2
3

# 约定路由

当一个页面建立好以后,如何能访问到这个页面 ? 也是一个不能忽视的问题。既然是约定开发,肯定是有一个约定的。 首先第一步,我们需要在项目根目录下的app.vue文件中,使用 <Nuxtpage> 标签,这就相当于路由的出口了。

<template>
  <div>
    <hello-world />
    <NuxtPage></NuxtPage>
  </div>
</template>
1
2
3
4
5
6

比如我们现在这个页面,想要访问到,其实只要在地址栏输入下面的地址就可以了。

http://localhost:3000/demo1
1

但是如果你使用原来的http://localhost:3000就又访问,会显示404,这时候你可以新建一个 index.vue 页面。

<template>
  <div class=""><h1>Index Page</h1></div>
</template>

<script setup>
import {} from "vue";
</script>

<style scoped></style>
1
2
3
4
5
6
7
8
9

这时候在访问http://localhost:3000就可以访问到页面了。

# NuxtLink标签的使用

Nuxt框架不鼓励我们使用<a> 标签进行跳转,而是使用<NuxtLink></NuxtLink>标签进行跳转。比如我们要从 index.vue页面跳转到demo1.vue页面,就可以使用下面的代码进行跳转。

<template>
  <div class="">
    <h1>Index Page</h1>
    <NuxtLink to="/demo1">Demo1.vue</NuxtLink>
  </div>
</template>
1
2
3
4
5
6

# 动态路由的使用

# 路由跳转

const router = useRouter()
router.push(路由地址)
1
2

# 单参数的传递

单参数的传递只要在页面的文件名中用[ ]扩起来就可以了。比如新建一个页面,叫做 demo2-[id].vue

-| pages/
---| index.vue
---| demo2-[id].vue
1
2
3

也就是说我们使用[ ]的形式就可以设置一个页面的传参。参数接收可以使用 $route.params.id的形式。

<template>
  <div class="">获取的id:{{ $route.params.id }}</div>
</template>

<script setup>
import { } from "vue";
</script>

<style scoped></style>
1
2
3
4
5
6
7
8
9

我们去首页制作一个链接。

<template>
  <div class="">
    <h1>Index Page</h1>
    <NuxtLink to="/demo1">Demo1.vue</NuxtLink> <br />
    <NuxtLink to="/demo2-38">Demo2.vue</NuxtLink>
  </div>
</template>

<script setup>
import {} from "vue";
</script>

<style scoped></style>
1
2
3
4
5
6
7
8
9
10
11
12
13

这时候再到浏览器预览一下,调整后能得到ID,可以了

# 在script里获取参数

上面只是在页面中获取了参数,实际作用并不大。工作中获取参数后,都要进行业务逻辑的处理,所以在<script>标签里获取参数,才是真实的开发需求。

<template>
  <div class="">获取的id:{{ id }}</div>
</template>

<script setup>
import { ref } from "vue";
const route = useRoute();
const id = ref(route.params.id);
</script>

<style scoped></style>
1
2
3
4
5
6
7
8
9
10
11

上面的代码通过useRoute( ) 获得了 route 然后通过ref让template可用。

# 多参数的获取

有人说是不是再写一个括号就可以传递多一个参数了,这种是不行的。如果你要传递是两个参数。你需要建立一个文件夹,然后在文件夹上使用[ ]来确定参数。比如我们要传递一个name的参数过来。就需要把目录和文件建立成这样。

-|  pages/
---| index.vue
---| goods-[name]/
-----| demo2-[id].vue
1
2
3
4

然后修改一些demo2-[id].vue的文件,修改获取的参数。

<template>
  <div class="">获取的id:{{ id }}</div>
  <div class="">获取的name:{{ name }}</div>
</template>

<script setup>
import { ref } from "vue";
const route = useRoute();
const id = ref(route.params.id);
const name = ref(route.params.name);
</script>

<style scoped></style>
1
2
3
4
5
6
7
8
9
10
11
12
13

再到index.vue 修改链接,传递两个参数。

<NuxtLink to="/goods-jspang/demo2-38">Demo2.vue</NuxtLink>
1

# 嵌套路由的使用

掌握了动态路由后,我们还需要对嵌套路由有所了解。嵌套路由就是路由是两级,但是程序员的页面是一个。也就是说有父级页面,也有子集页面。类似我们的页面嵌套。

# 如何建立一个嵌套路由

嵌套路由的建立非常容易,用一句话解释为:目录和文件名同名,就制作了一个嵌套路由。 制作一个嵌套路由页面一般需要三步:

  1. 建立嵌套路由的文件夹(约定大于配置)
  2. 创建和文件夹相同名称的文件(父页面)
  3. 在新建文件夹下任意创建子页面
|--pages
|----parent/
|------child.vue
|----parent.vue
1
2
3
4

先在\pages目录下,新建一个文件夹 parent ,然后在pages目录下再建立一个parent.vue的文件。文件建立好之后,编写代码。

<template>
  <div class="">Parent Page</div>
  <!-- 子页面的出口-->
  <NuxtChild></NuxtChild>
</template>

<script setup>
import {} from "vue";
</script>

<style scoped></style>
1
2
3
4
5
6
7
8
9
10
11

这里的<NuxtChild>就是嵌套路由的出口,所以如果是嵌套路由,就必须要加上这个标签。这是Nuxt的一个内置组件。 有了父页面之后,在新建的parent文件夹下,再建立一个 child.vue子页面。然后编写代码。

<template>
  <div class="">Child Page</div>
</template>

<script setup>
import {} from "vue";
</script>

<style scoped></style>
1
2
3
4
5
6
7
8
9

然后为了看到效果,我们还需要一个路由链接过来。直接到index.uve增加路由链接。

<NuxtLink to="/parent/child">/parent/child</NuxtLink><br />
1

做完这部,我们就可以到浏览器预览一下效果了。

# 多个子页面的制作

这时候小伙伴可能会有疑问了,如果我有多个子页面要如何作那?方法其实和制作一个单页面是相同的。在 \pages\parent\文件夹下面再新建一个文件 two.vue。然后编写代码。

<template>
  <div class="">Two Page</div>
</template>

<script setup>
import {} from "vue";
</script>

<style scoped></style>
1
2
3
4
5
6
7
8
9

写完后再到index.vue页面,增加导航路由。

<NuxtLink to="/parent/two">/parent/two</NuxtLink><br />
1

然后去浏览器查看结果。

# 自定义路由

文件路径app/router.options.ts

import type {RouterConfig} from '@nuxt/schema'

export default<RouterConfig> {
    routes:(_routes)=>[
        ..._routes,
        {
            name:'home',
            path:'/',
            component:()=>import('~/pages/home.vue')
        }
    ]
}
1
2
3
4
5
6
7
8
9
10
11
12

# 布局模板 让开发高效起来

布局模板的作用就是你先定义好一个布局页面,然后提取一些通用的UI或代码到可重用的模板中,提高代码复用性,从而降低代码的复杂度,让代码重用性提高。 简单说就是把一些通用的UI代码代码提出来,然后放在一个模板里,使用这个模板的每个页面都拥有这些代码UI了。

# 创建布局模板和使用模板

比如现在新建一个文件夹\layouts然后再里边写编写一个 defalut.vue文件,代码如下。

<template>
  <div>
    我是布局模板,default.vue
    <slot />
  </div>
</template>
1
2
3
4
5
6

上边这段代码就相当于你创建了一个布局模板。有了这个模板后,可以在任何你想要使用的页面中用<NuxtLayout>标签为页面赋予模板中的内容。比如我们想在每个页面中都赋予这个模板中的内容,就可以在 app.vue 页面中使用这个标签。

<template>
  <NuxtLayout name="default">
    <div>
      <hello-world />
      <NuxtPage></NuxtPage>
    </div>
  </NuxtLayout>
</template>
1
2
3
4
5
6
7
8

这样每个页面都会有布局模板中的效果,因为app.vue是每个页面的出口。

# 增加多个插槽

修改default.vue布局模板,增加第二个插槽,一个叫做one,一个叫做two。

<template>
  <div>
    我是布局模板,default.vue
    <slot name="one" />
    ---------
    <slot name="two" />
  </div>
</template>
1
2
3
4
5
6
7
8

这样编写,一个模板中就有了两个插槽,你可以在页面中通过<template #xxx>的形式来指定对应的模板插槽。 在index.vue中使用多个 <template> 配合模板实现多插槽。

<template>
  <NuxtLayout name="default">
    <template #one>
      <div class="">
        <h1>Index Page</h1>
        <NuxtLink to="/demo1">Demo1.vue</NuxtLink> <br />
        <NuxtLink to="/goods-jspang/demo2-38">Demo2.vue</NuxtLink><br />
        <NuxtLink to="/parent/child">/parent/child</NuxtLink><br />
        <NuxtLink to="/parent/two">/parent/two</NuxtLink><br />
      </div>
    </template>
    <template #two> 我是two中的内容 </template>
  </NuxtLayout>
</template>

<script setup>
import {} from "vue";
</script>

<style scoped></style>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

注意上面的页面就精确的对应了模板的插槽。如果你作的页面都非常相似,可以好好的利用这个模板布局。 这个插槽也可以是多个,只要名字对应正确就可以实现。

# 组件的编写

# Nuxt3中创建一个组件

Nuxt3的所有自定义组件,必须写在components目录下,写在这个目录下他会自动加载到页面中,而不用我们自己不断的重复引入到每个页面中。 比如现在要创建一个<TheFooter/> 的组件,我们在项目跟目录建立一个文件夹components ,然后建立一个文件TheFooter.vue

//目录结构
-|components
----|TheFooter.vue
1
2
3

然后在vscode中打开文件,编写下面的代码。

<template>
  <h1>The Footer Box</h1>
</template>
1
2
3

这段代码只有一个<h1> 标签,在页面中显示出了 The Footer Box 。写好组件后,你可以到任何的页面(page)中进行使用。比如在首页使用他们。 打开/pages/Index.vue页面,然后在最下面加入这个组件。

<template>
  <NuxtLayout name="default">
    <template #one>
      <div class="">
        <h1>Index Page</h1>
        <NuxtLink to="/demo1">Demo1.vue</NuxtLink> <br />
        <NuxtLink to="/goods-jspang/demo2-38">Demo2.vue</NuxtLink><br />
        <NuxtLink to="/parent/child">/parent/child</NuxtLink><br />
        <NuxtLink to="/parent/two">/parent/two</NuxtLink><br />
      </div>
    </template>
    <template #two>
      <div>我是two中的内容</div>
      <TheFooter />
    </template>
  </NuxtLayout>
</template>

<script setup>
import {} from "vue";
</script>

<style scoped></style>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

这时候你到浏览器中就可以看到我们刚写的<TheFooter/> 组件起作用了。

# 在布局模板中使用组件

底部,其实是每个页面都需要包括的组件,拿我们可以直接把这个组件放到布局模板里是非常合适的选择。在布局模板中使用组件和在普通页面中使用组件没有太大的差别,直接使用就可以了。 这里我们就在\layouts\default.vue布局模板中使用。

<template>
  <div>
    我是布局模板,default.vue
    <slot name="one" />
    ---------<br />
    <slot name="two" />
    <TheFooter />
  </div>
</template>
1
2
3
4
5
6
7
8
9

这时候每个使用了default.vue这个布局模板的页面就会有<TheFooter />这个组件的存在了。

# 组件名称的约定

我说了很多会了Nuxt3是约定大于配置的开发模式,所以我们要了解Nuxt3框架对于组件名字的约定。比如按照以前的经验,这个<TheFooter/> 组件,习惯写成 <the-footer /> 我们测试一下,如果你这样写在页面里也是生效的。

/layouts/default.vue
<template>
  <div>
    我是布局模板,default.vue
    <slot name="one" />
    ---------<br />
    <slot name="two" />
    <TheFooter />
    <the-footer />
  </div>
</template>
1
2
3
4
5
6
7
8
9
10
11

但是个人建议,你尽量使用大写,因为这样可以区分哪些是自定义组件,哪些是原生的HTML标签。 我说了这是个人建议,但不是必须的。你也可以编写一个the-header.vue 的组件,然后用 <the-header/> 的形式使用这个组件也是完全可以的。例如下面的两端代码。 在/components文件夹下面,新建一个页面 the-header.vuer

<template>
  <h1>The Header Box</h1>
</template>
1
2
3

然后回到layouts文件夹下的defalut.vue下使用。

<template>
  <div>
    <the-header />
    我是布局模板,default.vue
    <slot name="one" />
    ---------<br />
    <slot name="two" />
    <TheFooter />
    <the-footer />
  </div>
</template>
1
2
3
4
5
6
7
8
9
10
11

也是完全可以使用的。由此看来Nuxt3对于组件的使用还是非常方便的,你只要符合自己的习惯就好。

# 层级组件、懒加载组件的使用

多层级组件看似好像很复杂,也可能是我表述的不对,其实多层级组件就是把一个组件放在一个文件夹里。在实际工作中组件会非常多,所以会把组件分门别类的放置。那这种有层级的组件,我们要如何引用那。 比如在components文件夹下面,新建一个 test文件夹,然后在test文件夹下面再创建一个 MyButton.vue文件。

<template>
  <div class=""><button>MyButton</button></div>
</template>

<script setup>
import {} from "vue";
</script>

<style scoped></style>
1
2
3
4
5
6
7
8
9

写完这个组件后,最关键的一步,就是在页面里如何引用到这个组件。方法很简单,只要在这个页面的前面加上文件夹的名称就可以了。我们的目录结构如下:

--|components
----|test
------|MyButton.vue
1
2
3

那引用组件的方法就是这样的。

<TestMyButton />
1

如果有很多层级,我们也依照这个规律,加入前缀就可以实现多层级组件的引用了。 这种设计的目的是让框架可以应对复杂项目和多组件的需求,让我们的组件更加有条例。

# 组件的懒加载

如果在组件名前面加上Lazy前缀,则可以按需懒加载该组件。懒加载组件的目的是在项目打包的时候包更小。简单理解可以理解为只有在组件显示在页面上时才进行加载。 比如我们现在要做一个文本,这个文本只有在show的值为 true的时候才会显示。然后其他时候他不显示。

<lazyText v-if="show" />
1

这时候我们就可以使用懒加载组件。如果不总是需要该组件,这将特别有用。 在components文件夹下,新建一个 LazyText.vue的文件,然后编写代码如下。

<template>
  <div class="">Lazy Text Content</div>
</template>

<script setup>
import {} from "vue";
</script>

<style scoped></style>
1
2
3
4
5
6
7
8
9

有了组件之后,我们在新建一个页面demo2.vue。然后用一个按钮来控制这个组件的显示和隐藏。

<template>
  <div class="">
    <lazyText v-if="show" />
    <button @click="handleClick">显示/隐藏</button>
  </div>
</template>

<script setup>
import { ref } from "vue";
const show = ref(false);
const handleClick = () => {
  show.value = show.value ? false : true;
};
</script>

<style scoped></style>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

然后到浏览器看一下效果,这种就是懒加载组件的使用。这种组件也可以用来优化页面的打开速度,比如你有一个几百行的长列表。直接加载会给服务器造成很大压力,如果在其他内容已经完成后,过1-2秒再加载这个长列表,就会给用户很好的体验。也会减少服务器的压力。 组件相关的内容还是挺多的,所以我们下节课还是学习Nuxt3组件相关的知识。

# 模块化代码 Composable文件夹的试用

在开发中我们经常会有一些通用的业务逻辑代码,需要模块化管理,这时候就可以试用Composable 这个文件夹来编写。比如我们常用的显示当前时间,这种常用的通用代码,就可以编写成一个单独的代码段,然后在每个页面进行使用。

# Composable中创建time.ts的编写

新建一个文件夹composables 然后在文件夹里边,新建一个文件time.ts ,然后编写下面的代码。这段代码你一定编写过,所以就不给大家讲解里边的具体含义了。你可以直接复制这段代码。

export  const getTime=()=>{
  const timezone = 8;
  const offset_GMT = new Date().getTimezoneOffset();
  const nowDate = new Date().getTime();
  const today = new Date(nowDate + offset_GMT * 60 * 1000 + timezone * 60 * 60 * 1000);
  const date = today.getFullYear() + "-" + twoDigits(today.getMonth() + 1) + "-" + twoDigits(today.getDate());
  const time = twoDigits(today.getHours()) + ":" + twoDigits(today.getMinutes()) + ":" + twoDigits(today.getSeconds());
  const timeString ='当前时间:' + date + '  ' + time;

  return timeString;

}

function twoDigits(val) {
  if (val < 10) return "0" + val;
  return val;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

写完之后,如何在页面中使用呢?在pages 文件夹下面,新建一个\pages\demo3.vue 的文件,然后你就可以直接在这个页面中使用刚才写的获得时间的方法了。

<template>
  <div class="">{{ time }}</div>
</template>

<script setup>
import { ref } from "vue";
const time = ref(getTime());
</script>

<style scoped></style>
1
2
3
4
5
6
7
8
9
10

打开浏览器就可以获得当前时间了。 你可以把任何你在项目中经常使用的代码,封装到这个文件夹里,实现代码的复用。这个文件夹的功能和组件很相似,只是组件是UI部分的代码复用,而这个是业务逻辑代码的复用。

# composables的引入规则

composables 文件夹的引入规则是,只有顶层文件会被引入。也就是说我们如果在这个文件下再新建一个文件夹,是不会被引入到 页面中实现代码复用的。 比如下面的文件格式就没办法引入。

--|composables
----|test
------|test.ts
1
2
3

但是有一种是例外的,就是我们可以写成下面的这种形式。

--|composables
----|test
------|index.ts
1
2
3

我们这里测试一下,新建一个\test 文件夹,然后在它的下面再创建一个index.ts 文件。写入下面的代码。

export const test = ()=>{
  console.log('jspang.com')
}
1
2
3

然后回到Demo3.vue 页面使用test( ) 方法,结果是可以使用这个方法的。

<template>
  <div class="">{{ time }}</div>
</template>

<script setup>
import { ref } from "vue";
const time = ref(getTime());
test();
</script>

<style scoped></style>
1
2
3
4
5
6
7
8
9
10
11

我们在\test 文件夹下面,再新建一个test.ts 文件,然后编写代码,如下:

export const testTwo = ()=>{
  console.log('我是技术胖')
}
1
2
3

你会发现,这种形式是不能直接引入到页面当中进行使用的,会直接报错testTwo is not defined.也就是找不到这个方法。

# 数据请求

Nuxt3中提供了四种方法:useAsyncDatauseFetchuseLazyFetchuseLazyAsyncData 。提供的四个方法,都是获取后台数据的,但是使用场景和使用方法有所不同。

# useAsyncData的使用

使用useAsyncData 异步获取数据,它可以使用在页面中,组件和插件中。我们先通过这个方法来获取一下服务端的数据。 在pages文件夹下,新建一个页面,然后编写下面的代码。

<template>
  <div class=""></div>
</template>

<script setup>
import {} from "vue";

const res = await useAsyncData("getList", () =>
  $fetch("http://121.36.81.61:8000/getTenArticleList")
);
console.log(res);
</script>

<style scoped></style>
1
2
3
4
5
6
7
8
9
10
11
12
13
14

$fetch( )方法是nuxt3提供的内置方法,我们直接可以使用。

写完后,可以打开浏览器的调试面包,在终端里可以看到返回值是一个对象,对象里有四个属性。

  • data: 返回的数据,我们需要的服务器数据就在这个属性里。
  • error:是否存在错误,如果存在错误,可以在这个属性中获得,返回的是一个对象。
  • pending:这次请求的状态,返回的是布尔值。
  • refresh:这个返回的是一个函数,可以用来刷新 handler函数返回的数据。

这个方法的一个特点是,它可以进行很多选项的配置,但是在真实开发中,其实我们用的不多。最常用的就是lazy 选项,比如我们设置成true 就是需要数据都返回后,才会显示出来 ,简单说就是会阻塞页面。默认是false。 比如要设置lazy为true,就可以这样写。因为我们的数据太少,所以基本看不出来效果。

const res = await useAsyncData(
  "getList",
  () => $fetch("http://121.36.81.61:8000/getTenArticleList"),
  {
    lazy: true,
  }
);
1
2
3
4
5
6
7

这个可配置的选项option 其实还是挺多的,有七项。如果想详细了解的,可以到官方去看一下,我这里给出地址。https://v3.nuxtjs.org/api/composables/use-async-data

但这些选项在开发中很少被配置,一般都使用默认值。所以Nuxt3又提供了一个简单的方法useFetch

# useFetch的使用

useFetch 可以理解为所有的都选择默认配置的useAsyncData 方法。比如还是上面的请求,我们就可以写成下面的形式。

const res = await useFetch("http://121.36.81.61:8000/getTenArticleList");
1

这样我们依然可以获取数据,当然也是可以传递参数和配置请求方法的。比如我们要设置请求方法是get,传递id是1, 就可以写成下面的形式。

const res = await useFetch("http://121.36.81.61:8000/getTenArticleList", {
  method: "get",
  id: 1,
});
1
2
3
4

现在我们要把获取到的数据,显示在页面上。修改一下程序,定义变量,然后用ref来赋值就可以了。

<template>
  <div class="">{{ list }}</div>
</template>

<script setup>
import { ref } from "vue";

const res = await useFetch("http://121.36.81.61:8000/getTenArticleList");
const list = ref(res.data._rawValue.data);
console.log(res);
</script>

<style scoped></style>
1
2
3
4
5
6
7
8
9
10
11
12
13

这样就可以在页面上看到这些从后端得到的数据了。在实际开发中,我们会把这个数组循环输出,并制作一个精美的列表。 当我们会使用了useAsyncDatauseFetch 这两个方法后,useLazyAsyncDatauseLazyFetch 也自然会使用了。他们只是把配置选项中的Lazy 设置成了true, 也就是会阻塞页面。

# middleware路由中间件

Nuxt3提供了路由中间件的概念,你可以在整个应用使用它,目的是在导航到某一个页面之前,执行一些代码。最常见的路由守卫就可以用这个实现。

# 中间件的基本格式

我们先写一个最简单的中间件,就是在控制台打印来的页面,和要去的页面。目的是通过最简单的实例来了解中间件的基本格式。 在项目根目录,新建一个middleware的文件夹,然后在文件下边新建一个文件default.global.ts 的文件。其中的.global代表这个中间件是全局的,也就是在每次跳转都会执行下面的代码。

export default defineNuxtRouteMiddleware((to, from) => {
  console.log("要去那个页面:"+to.path)
  console.log("来自那个页面:"+from.path)
})
1
2
3
4

写完之后,我们可以到浏览器看一下效果。如果一切正常,你可以看到,这时候你在每次跳转时,都会在终端中打出结果。 当然我们可以继续编写代码,看看tofrom里到底都有什么属性。

export default defineNuxtRouteMiddleware((to, from) => {
  console.log("要去那个页面:"+to.path)
  console.log(to)
  console.log("来自那个页面:"+from.path)
  console.log(from)
})
1
2
3
4
5
6

可以看到里边的内容是非常多的,特别是to的时候,你可以根据这些来进行编程。

# 通过中间件 设置路由守卫

当我们了解路由中间件的基本写法后,在增加一些难度,来模仿一下路由守卫。比如我们要访问的页面是http://localhost:3000/demo1,现在设置路由守卫,不允许访问,而是跳回到首页。那代码就可以写成下面的样子。

export default defineNuxtRouteMiddleware((to, from) => {
  if (to.path === '/demo1') {
     console.log('禁止访问这个页面')
     abortNavigation()  //停止当前导航,可以使用error进行报错
     return  navigateTo('/')
  }
})
1
2
3
4
5
6
7

这时候再到浏览器访问demo1 页面,已经不能访问了,但其他页面是可以访问的。

# 只对一个页面起作用

上面都是对所有路由起作用的,如果只想中间件对一个特殊页面起作用,也是可以的。只要去掉.global的后缀就是可以的。 在middleware 文件夹下,新建一个页面,default.ts,并编写下面的代码。

export default defineNuxtRouteMiddleware((to, from) => {
  console.log("Hello JSPang.com")
})
1
2
3

这时候它对任何页面都是不起作用的,你需要再去对应的页面里注册一下。去pages文件夹,新建一个文件demo7.vue。然后需要注册这个页面使用这个中间件,代码如下。

<template>
  <div class="">Demo7 Page</div>
</template>

<script setup>
definePageMeta({
  middleware: ["default"],
  // or middleware: 'auth'
});
</script>

<style scoped></style>
1
2
3
4
5
6
7
8
9
10
11
12

这样就对这个页面注册了一个专属的导航中间件。

# SEO相关的配置

# Nuxt3中的useHead 和useMeta

Nuxt3中提供了 useHead方法来设置SEO需要的内容,用它可以设置HTML中Head的全部内容,所以这也包括meta标签的内容,基本的使用方法也是很简单。 上节课我们新建了一个Nuxt3的项目,这节我们就在上节课的项目中继续。在练习的根目录中下的 page文件夹下,新建一个文件demo1.vue,然后使用 useHead( )方法来设置头部信息。

<template>
  <div class="">Demo8 Page</div>
</template>

<script setup>
useHead({
  title: " JSPang.com 技术胖的博客",
  viewport: "width=device-width,initial-scale=1,maximum-scale=1 ",
  charset: "utf-8",
  meta: [
    { name: "description", content: "技术胖的前端免费视频博客" },
    { name: "keywords", content: "技术胖" },
  ],
});
</script>

<style scoped></style>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

# 使用template中的标签定义Head

除了使用useHead( ) 方法外,你还可以直接使用<template> 中的的<head>来定义SEO相关的属性。 我们在/pages 文件夹下面,新建一个demo1.vue 的文件,然后编写下面的代码。

<template>
  <div class="">
    <Head>
      <Title>{{ title }}</Title>
      <Meta name="description" :content="title" />
    </Head>
    <div>技术胖的博客</div>
  </div>
</template>

<script setup>
import { ref } from "vue";
const title = ref("技术胖的博客");
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14

从代码中可以看到,我们直接使用了<Head>标签,然后在里边还可以使用<Title>标签和<Meta>标签,可以设置这两个标签后,关于SEO的设置就都可以作了。 我们使用Nuxt的意义就在于可以有很好的SEO效果,所以在你开发的时候,一定要对页面进行标题、描述和关键词的设置和编写。

# Cookie的设置

在网页制作时,经常需要临时保存一些信息到Cookie中,而不是全部都保存到数据库中,这样作能减轻服务器的压力。这节就学习一下Nuxt3中的Cookie操作。

# cookie的作用

先来了解一下Cookie的作用,Cookie最常见的开发作用就是临时记录用户个人信息,比如我们登录了一个网站,然后提醒下次记住信息,下次再浏览这个网站时,就不用登录了。 这就是cookie起的作用,当我们登录一次后,把登录信息记录在了cookie里,但是这个记录是有时效性的,通过属性可以进行设置。比如你连续7天没登录,那cookie就过期了,再浏览这个网站就需要重新登录了。

# useCookie( )方法的使用

const cookie = useCookie(name, options)
1

制作登录太复杂,我们这属于是入门的教程,所以就用Cookie制作一个计数器,让你了解Cookie的使用方法。这里要使用的函数就是useCookie ,代码如下。 在pages 文件夹下,新建一个页面demo3.vue

<template>
  <h1>Counter:{{ counter }}</h1>
  <button @click="reset">Reset</button>
  <button @click="add">Add</button>
</template>

<script setup>
const counter = useCookie("counter");
counter.value = counter.value || 0;
const reset = () => {
  counter.value = 0;
};
const add = () => {
  counter.value = counter.value + 1;
};
</script>

<style scoped></style>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

这段代码的意思,我创建了一个叫做counter的Cookie值,然后取得Cookie值,放到页面上,如果没有Cookie值的时候,就初始化Counter的Cookie值为0。然后我又作了两个按钮,一个是直接将Cookie值设置为0,一个是每点击一次Cookie加1。 代码编写完成后,可以到浏览器中查看一下效果,你也可以按F12打开浏览器的调试模式,找到Application 标签,再找到Cookie 选项,就可以看到里边的Cookie值了,这也很好的证明我们的Cookie值设置成功了。

# 常用的相关属性

useCookie( )函数,第一个参数是设置Cookie值的名字,第二个参数为选项option,我们接着来看有那些可选择配置的Cookie参数。(注意:我这里只说两个常用的)

  1. maxAge/expires

这两个参数都是设置Cookie的有效时长的,如果两个参数你都不设置,那Cookie的值在关闭浏览器的时候将会被清空。两个参数的不同是,maxAge的值是一个数字Number,而expires的值是一个日期对象Date object. 比如我们希望设置Cookie的过气时间是一个小时,也就是3600秒,那我们的配置就需要这样写。

const counter = useCookie("counter",{
  maxAge:3600,
});
1
2
3

\2. httpOnly 这算是一个安全设置,如果把httpOnly设置为true,可以对最常见的XSS攻击起到防范作用。

什么是HttpOnly? HttpOnly是包含在http返回头Set-Cookiew里面的一个附件的flag,所以它是后端服务器对cookie设置的一个附件属性,在生成cookie时使用HttpOnly标志有助于减轻客户端脚本访问收保护cookie的风险。

const counter = useCookie("counter",{
  htttpOnly:true,
});
1
2
3

\3. secure 这也是一个安全设置,如果你的网址不是HTTPS的,并且把secure的值设置为true,那Cookie的值就不会传递给服务端。总的来说还是一个为了服务器安全的设置。

const counter = useCookie("counter",{
  secure:true,
});
1
2
3

这个需要配置HTTPS 所以不太好演示,这里也就不演示了。 其余的还有domain ,path ,sameSite ,encode,decode 这些属性设置,其实都跟安全有关,因为Cookie的设置确实需要考虑安全性,所以根据服务端和app的需求,尽量设置多的安全性参数。

# 服务端接口编写

# 状态管理

# 部署

# 静态托管-仅客户端渲染

如果你不想预渲染你的路由,另一种使用静态托管的方法是在nuxt.config配置文件中设置 ssr属性为falsenuxi generate命令会输出一个.output/public/index.html入口点和JavaScript包,就像一个经典的客户端Vue.js应用程序一样。

defineNuxtConfig({ 
    ssr: false
})
1
2
3

# 引入Pinia

# 引入 Element Plus

上次更新: 15 minutes