拥抱全栈框架 Nuxt | 基础篇

8,062 阅读8分钟

前言

nuxt.png nuxt3.png

Nuxt 官网表示,Nuxt 是一个开源框架,使 Web 开发直观而强大。使用 Nuxt 可以自信地创建高性能和生产级的全栈 Web 应用程序和网站,并且得到众多知名公司前端团队的信任。

Nuxt 是前端工程师进阶全栈工程师的必由之路,值得一提的是,Nuxt 框架是基于 Vue 生态的上层封装并且帮我们内置了很多功能,只要熟悉 Vue 技术栈和 Node 基础,就可以快速上手 Nuxt。

我的另一篇文章拥抱全栈框架 Nuxt | 配置篇详细讲解了如何创建 Nuxt 项目并配置项目,而这一篇拥抱全栈框架系列的基础篇,结合着文章和 Nuxt 官网,我相信掌握 Nuxt 基础不是一件难事。

Nuxt 基础知识

Nuxt 内置组件

Nuxt3 框架也提供一些内置的组件,常用的如下:

NuxtLayout:是 Nuxt 自带的页面布局组件。

NuxtWelcome:欢迎页面组件,该组件是 @nuxt/ui 的一部分。

ClientOnly:该组件中的默认插槽的内容只在客户端渲染,而fallback插槽的内容只在服务器端渲染。

<template>
  <div class="home">
    <div>我是Home Page</div>
    <ClientOnly>
      <div>我只会在 client 渲染</div>
      <template #fallback>
        <h2>服务器端渲染的 loading 页面</h2>
      </template>
    </ClientOnly>
  </div>
</template>

NuxtLink:是 Nuxt 自带的页面导航组件,是 Vue Router<RouterLink>组件 和 HTML<a>标签的封装。

SEO组件<Title><Base><NoScript><Style><Meta><Link><Body><Html> and <Head>

NuxtPage:是 Nuxt 自带的页面占位组件,需要显示位于目录中的顶级或嵌套页面 pages/ 目录中,是对 router-view 的封装。

<template>
  <div>
    <h1>App</h1>
    <!--是 对 router-view 封装 -->
    <NuxtPage></NuxtPage>
  </div>
</template>

全局样式

编写全局样式、全局变量步骤

  1. 在 assets 文件中编写全局样式,比如:globel.scss;
// 全局样式
$color: blue;

.global-style {
  color: $color;
}
  1. 在 assets 文件中编写全局样式变量,比如: variables.scss;
// 定义全局的SCSS变量
$fsColor: purple;
$fs20: 20px;
// 混合
@mixin border() {
  border: 1px solid red;
}
  1. 在 nuxt.config 中的 css 选项、vite 选项中进行配置,使定义的全局样式和全局变量生效
// https://nuxt.com/docs/api/configuration/nuxt-config
export default defineNuxtConfig({
  // 定义全局样式
  css: [
    "@/assets/styles/global.scss"
  ],
  // 定义全局变量
  vite: {
    css: {
      preprocessorOptions: {
        scss: {
          // 自动的给 scss 模块首行添加额外的数据: @use "@/assets/styles/variables.scss" as *;
          additionalData: '@use "@/assets/styles/variables.scss" as *;',
        },
      },
    },
  },
});
  1. 接着在命令行终端执行 npm i –D sass 即可,然后就可以在任意组件中或 scss 文件中直接使用全局变量

资源的导入

public目录

用作静态资源的公共服务器,可以在应用程序上通过 URL 直接访问

例如,引用 public/img/ 目录中的图像文件,在静态 URL 中可用 /img/nuxt.png 表示

<template>
  <div>
    <!-- public 资源的访问 -->
    <img src="/img/nuxt.png" alt="" />
  </div>  
</template>

静态的 URL 也支持在背景中使用,如 background-image: url(/logo.png)

assets目录

assets 经常用于存放如样式表、字体或 SVG 等资源

可以直接使用 ~/assets/ 路径引用位于 assets 目录中的资源文件

<template>
  <div>
    <!-- assets 资源的访问 -->
    <img src="@/assets/images/avatar.png" alt="" />
    <img src="~/assets/images/avatar.png" alt="" />
  </div>  
</template>

其实 ~/assets/ 路径也支持在背景中使用,如background-image: url(@/assets/images/avatar.png)

新建页面

Nuxt 项目中的页面是在 pages 目录下创建的

在 pages 目录创建的页面,Nuxt 会根据该页面的目录结构和其文件名来自动生成对应的路由

页面路由也称为文件系统路由器(file system router),路由是 Nuxt 的核心功能之一

新建页面步骤

  1. 创建页面文件,比如: pages/index.vue
  2. <NuxtPage /> 内置组件添加到 app.vue
  3. 页面如果使用 scss 那么需要安装: npm i sass -D

命令快速创建页面

  1. npx nuxi add page home 用来创建 home 页面
  2. npx nuxi add page detail/[id] 用来创建 detail 页面
  3. npx nuxi add page user-[role]/[id] 用来创建 user 页面

组件导航(NuxtLink)

<NuxtLink> 是 Nuxt 内置的组件,用来实现页面导航,本质上是对 RouterLink 的扩展,底层用的是一个 <a> 标签,因此使用 a + href 属性也支持路由导航。与 <NuxtLink> 不同的是,用 a 标签导航会有触发浏览器默认的刷新事件,而 <NuxtLink> 不会, <NuxtLink> 还扩展了其它的属性和功能,因此在 Nuxt 中我们可以使用 <NuxtLink> 进行组件之间的导航。

<NuxtLink> 组件的部分属性:

  1. to 支持路由路径、路由对象、 URL
<template>
  <NuxtLink to="/about">
    About page
  </NuxtLink>
  <!-- <a href="/about">...</a> (+Vue Router & prefetching) -->
  
  <!-- 以路由对象的形式传入 -->
    <NuxtLink
      :to="{
        path: '/category',
        query: {
          id: 100
      }
    }"
   >
     <button>category</button>
   </NuxtLink>
</template>
  1. href to 的别名
  2. target 和 a 标签的 target 一样,指定何种方式显示新页面
<template>
  <NuxtLink href="https://www.nuxt.com" target="_blank">
    <button>nuxt.com</button>
  </NuxtLink>
</template>
  1. replace 默认为 false,是否替换当前路由
<template>
  <NuxtLink href="/find" replace>
    <button>find replace</button>
  </NuxtLink>
</template>
  1. activeClass 激活链接的类名
<template>
  <NuxtLink to="/home" active-class="active-home">
    <button>home</button>
  </NuxtLink>
</template>

编程式导航

navigateTo

Nuxt3 除了可以通过 <NuxtLink> 内置组件来实现导航,同时也支持编程导航:navigateTo,通过编程式导航,在应用程序中就可以轻松实现动态导航了,但是编程式导航不利于 SEO。navigateTo 函数在服务器端和客户端都可用,可以在插件、中间件中使用,也可以直接调用执行页面导航

其中 navigateTo( to , options) 函数包含两个参数

第一个参数 to 可以是纯字符串或外部 URL 或路由对象;

第二个参数 options 为导航配置

  1. replace:默认为 false,为 true 时会替换当前路由页面
  2. external:默认为 false,不允许导航到外部连接,true 则允许

在 Vue 组件中直接使用

<script setup lang="ts">
// passing 'to' as a string
await navigateTo('/search')

// ... or as a route object
await navigateTo({ path: '/search' })

// ... or as a route object with query parameters
await navigateTo({
  path: '/search',
  query: {
    page: 1,
    sort: 'asc'
  }
})
</script>

在中间件中使用

export default defineNuxtRouteMiddleware((to, from) => {
  if (to.path !== '/search') {
    // setting the redirect code to '301 Moved Permanently'
    return navigateTo('/search', { redirectCode: 301 })
  }
})

useRouter

Nuxt3 中的编程导航除了可以通过 navigateTo 来实现导航,同时也支持 useRouter (或 Options API 的 this.$router)。

useRouter 常用的 API:

  1. back:页面返回,同 router.go(-1)
  2. forward:页面前进,同 router.go(1)
  3. go:页面返回或前进,如 router.go(-1) or router.go(1)
  4. push:以编程方式导航到新页面,建议改用 navigateTo,支持性更好
  5. replace:以编程方式导航到新页面,但会替换当前路由,建议改用 navigateTo,支持性更好
  6. beforeEach:路由守卫钩子,每次导航前执行(用于全局监听)
  7. afterEach:路由守卫钩子,每次导航后执行(用于全局监听)
<template>
  <div>
    <!-- 通过编程的方式进行导航 -->
    <button @click="goToHome">Go Home</button>
  </div>
  <!-- 是对router-view的封装 -->
  <NuxtPage></NuxtPage>
</template>
<script setup>
// useRouter
let router = useRouter();
function goToHome() {
  router.push("/home")
}

function goBack() {
  router.go(-1);
}

// 路由的守卫
router.beforeEach((to, form) => {
  console.log(to)
  console.log(form)
})
</script>

动态路由

Nuxt3 和 Vue 一样,也是支持动态路由的,在 Nuxt3 中,动态路由是根据目录结构和文件的名称自动生成

动态路由语法:

  1. 页面组件目录或页面组件文件都 支持 [ ] 方括号语法
  2. 方括号里编写动态路由的参数

例如,动态路由支持如下写法:

  1. pages/detail/[id].vue -> /detail/:id
  2. pages/detail/user-[id].vue -> /detail/user-:id
  3. pages/detail/[role]/[id].vue -> /detail/:role/:id
  4. pages/detail-[role]/[id].vue -> /detail-:role/:id

路由参数( useRoute )

动态路由参数

通过 [ ] 方括号语法定义动态路由,比如: /detail/[id].vue

页面跳转时,在 URL 路径中传递动态路由参数,比如: /detail/100

目标页面通过 route.params 获取动态路由参数。

示例:导航页面

<template>
  <div>
    <NuxtLink to="/detail/100">
      <button>detail</button>
    </NuxtLink>
    <!-- router-view -->
    <NuxtPage></NuxtPage>
  </div>
</template>

示例:获取数据页面

<template>
  <div>id={{ id }}</div>
</template>
<script lang="ts" setup>
  // 拿到动态路由的参数
  const route = useRoute()
  const { id } = route.params
</script>
<style scoped></style>

查询字符串参数

页面跳转时,通过查询字符串方式传递参数,比如: /detail/100?name=zhangsan

目标页面通过 route.query 获取查询字符串参数。

示例:导航页面

<template>
  <div>
    <NuxtLink to="/detail/100?name=zhangsan">
      <button>detail</button>
    </NuxtLink>
    <!-- router-view -->
    <NuxtPage></NuxtPage>
  </div>
</template>

示例:获取数据页面

<template>
  <div>id={{ id }} name={{ name }}</div>
</template>
<script lang="ts" setup>
  // 获取动态路由的参数
  const route = useRoute()
  const { id } = route.params
  const { name } = route.query
</script>
<style scoped></style>

路由匹配规则

路由匹配需注意的事项,预定义路由优先于动态路由,动态路由优先于捕获所有路由

预定义路由:pages/detail/create.vue

  1. 将匹配 /detail/create

动态路由:pages/detail/[id].vue

  1. 将匹配 /detail/1/detail/abc
  2. 但不匹配 /detail/create/detail/1/1/detail/

捕获所有路由:pages/detail/[...slug].vue

  1. 将匹配 /detail/1/2, /detail/a/b/c
  2. 但不匹配 /detail

总结

Nuxt 框架是开箱即用的,并且学习成本也非常低,我们需要做的事情 Nuxt 都帮我们做好了,因此我们只要专注于业务的开发,而无需关心那些繁琐的配置。

对于一些内置的 API,我们不需要导入就可以直接使用;对于注册路由,我们直接使用 Nuxt 给我们提供的动态路由就可以直接导航到相应的页面,并直接获取路由参数;对于代码规范,Nuxt 也帮我们内置好了,布局相关的组件,我们直接只用 layout,有关中间件相关的,我们直接在 middleware 文件夹下定义。

Nuxt 相关的知识点不止这些,我们打开 Nuxt 官网大致浏览一下就会发现,内容非常丰富,知识点非常多,不过不用焦虑,由浅入深,分章节去学习是最好的方式。在下一篇文章《拥抱全栈框架 Nuxt | 进阶篇》中,我们会学习到 Nuxt 的页面渲染、插件开发、如何书写中间件、如何发送网络请求获取数据、如何写 API 接口、如何引入状态管理库 Pinia,以及如何引入第三方组件库等内容。