Nuxt的基本使用

504 阅读8分钟

Nuxt是什么

  • Nuxt是一个基于Vue.js的通用应用程序,通过对客户端服务端基础架构的抽象组织,Nuxt主要关注的是应用的UI渲染。作为框架,Nuxt为客户端、服务端这种典型的应用架构模式提供了许多有用的特性,例如异步加载数据中间件支持布局支持等。
  • Nuxt预设了利用vue.js开发服务端渲染的应用所需的各种配置,除此之外,我们还提供了一种命令叫nuxt generate,为基于vue.js的应用提供生成对应的静态站点的功能。

为什么要使用Nuxt

我们或多或少都听过 Vue 写的 SPA 应用 SEO 不太好,为啥不好呢?实际上我们去搜索引擎搜一个问题时,搜索引擎会去“爬取”所有相关的内容,然后对内容进行排序,而爬虫爬取的是 HTML,SPA 应用服务器响应的一般是只有根节点的容器,里面的内容在完成数据填充后才有,爬虫爬不到东西,自然不会优先显示你的网页,而通过 SSR 响应的 HTML 是完整的,很利于爬虫的采集。

Nuxt的实现原理就是模拟一个服务端把Vue框架的代码执行完,然后返回给客户的浏览器。

如何使用

脚手架创建项目

npx create nuxt-app <项目名> 或者 yarn create nuxt-app <项目名>
它会让你进行一些选择:
  1. 在集成的服务器端框架之间进行选择:None (Nuxt默认服务器)ExpressKoaHapiFeathersMicroFastifyAdonis (WIP)
  2. 选择您喜欢的UI框架:None (无)BootstrapVuetifyBulmaTailwindElement UIAnt Design VueBuefyiViewTachyons
  3. 选择您喜欢的测试框架:None (随意添加一个)JestAVA
  4. 选择你想要的Nuxt模式 (Universal or SPA)
  5. 添加 axios module 以轻松地将HTTP请求发送到您的应用程序中。
  6. 添加 EsLint 以在保存时代码规范和错误检查您的代码。
  7. 添加 Prettier 以在保存时格式化/美化您的代码。

运行项目

yarn dev 或者 npm run dev

Nuxt就会创建一个.nuxt文件夹,里面准备好了部署服务器上的所有东西。

页面布局

-| assets/ 资源目录,用于存放未编译的静态资源,例如less,js等
-| components/ vue组件目录
-| layouts/ 布局组件目录
-| pages/ 页面目录,所有的vue试图。nuxt自动生成对应的路由
-| plugins/ 插件目录
-| static/ 静态目录
-| store/ vuex目录
-| nuxt.config.js nuxt个性化配置文件,内容将默认覆盖
-| package.json 用于描述应用的依赖关系和对外暴露的脚本接口。

该文件不能被重命名。

路由

Nuxt.js 依据 pages 目录结构自动生成 vue-router 模块的路由配置。

要在页面之间使用路由,我们建议使用 <nuxt-link> 标签。例如:

<template>
<nuxt-link to="/">首页</nuxt-link> 
</template>

动态路由

如果此时pages结构如下所示:

QQ图片20221129094419.png

Nuxt自动生成的路由配置表为:

router: { 
routes: [ 
{ name: 'index', path: '/', component: 'pages/index.vue' }, 
{ name: 'users-id', path: '/users/:id?', component: 'pages/users/_id.vue' },
{ name: 'slug', path: '/:slug', component: 'pages/_slug/index.vue' }, 
{ name: 'slug-comments', path: '/:slug/comments', component: 'pages/_slug/comments.vue' }
] }
  • 你会发现名称为 users-id 的路由路径带有 :id? 参数,表示该路由是可选的。如果你想将它设置为必选的路由,需要在 users/_id 目录内创建一个 index.vue 文件。
  • 你也可以通过 vue-router 的子路由创建 Nuxt.js 应用的嵌套路由。 创建内嵌子路由,你需要添加一个 Vue 文件,同时添加一个与该文件同名的目录用来存放子视图组件。 Warning: 别忘了在父组件(.vue文件) 内增加 <nuxt-child/> 用于显示子视图内容。

如果你想要改变Nuxt自动生成的路由配置,在nuxt.config.js文件中修改路由配置:

通过extendRoutes添加自定义路由:

router:{
 extendRoutes(routes, resolve){
      // 清空数组
      routes.splice(0);
      
      // 插入新的路由配置
      routes.push({...这里放你自己想要的路由配置}
 }
}

异步数据

  • asyncData方法

Nuxt.js 扩展了 Vue.js,增加了一个叫asyncData的方法,使得我们可以在设置组件的数据之前能异步获取或处理数据。

asyncData方法会在组件(限于页面组件)每次加载之前被调用。它可以在服务端或路由更新之前被调用。 在这个方法被调用的时候,第一个参数被设定为当前页面的上下文对象,你可以利用 asyncData方法来获取数据,Nuxt.js 会将 asyncData 返回的数据融合组件 data 方法返回的数据一并返回给当前组件。

注意:由于asyncData方法是在组件 初始化 前被调用的,所以在方法内是没有办法通过 this 来引用组件的实例对象。

Nuxt.js 提供了几种不同的方法来使用 asyncData 方法,你可以选择自己熟悉的一种来用:

  1. 返回一个 Promise, nuxt.js会等待该Promise被解析之后才会设置组件的数据,从而渲染组件。
export default { 
asyncData ({ params }) {
return axios.get(`https://my-api/posts/${params.id}`) 
.then((res) => {

return { title: res.data.title } 
// 或者使用回调函数 
// callback(null, { title: res.data.title })

}) } }
  1. 使用 async 或 await。
export default {
async asyncData ({ params }) { 
const { data } = await axios.get(`https://my-api/posts/${params.id}`)
return { title: data.title }
 }
}
  1. 如果组件的数据不需要异步获取或处理,可以直接返回指定的字面对象作为组件的数据。
export default { 
data () {
return { 
title: 'bar';
  }
 }
}
  • fetch方法

fetch 方法用于在渲染页面前填充应用的状态树(store)数据, 与 asyncData 方法类似,不同的是它不会设置组件的数据。

如果页面组件设置了 fetch 方法,它会在组件每次加载前被调用(在服务端或切换至目标路由之前)。

fetch 方法的第一个参数是页面组件的上下文对象 context,我们可以用 fetch 方法来获取数据填充应用的状态树。为了让获取过程可以异步,你需要返回一个 Promise,Nuxt.js 会等这个 promise 完成后再渲染组件。

警告: 您无法在内部使用this获取组件实例,fetch是在组件初始化之前被调用

<template> 
<h1>Stars: {{ $store.state.stars }}</h1> 
</template> 
<script> 
export default {
fetch ({ store, params }) 
 { 
  return axios.get('http://my-api/stars') 
  .then((res) => { store.commit('setStars', res.data)
})
 } 
} 
</script>

注意: 在nuxt 2.12版本之后,fetch中可以使用this,且没有第一个参数context,可以通过this.$nuxt.contxnt 获取上下文对象context,此时fetch是一个在服务端渲染期间组件实例被创建之后被调用,在客户端导航时被调用的钩子,有时也在组件挂载后。

中间件

middleware文件夹包含你应用的所有中间件。中间件让我们自定义一些方法,在页面page或者模板layout渲染前运行。就是一个函数,会在每一次请求路由之前被执行,可以用来做权限验证。

  • 默认参数context
export default function (context){
// Add the userAgent property to the context
context.userAgent = process.server?context.req.headers['user-agent'] : navigatoruserAgent
}
  • 使用

中间件的文件名就是中间件的名字 在通用模式下,中间件会在服务端被调用一次(第一次请求时,刷新页面时),跳转路由时在客户端被调用。 中间件会按照下面的顺序依次执行

  1. nuxt.config.js中的middleware(Router Middleware路由中间件)

    注意:在nuxt.config.js中配置中间件,需要添加以router.middleware的形式添加,因为中间件本来就是在路透切换中使用的

export default{
router:{
middleware:'name'
 }
}
  1. 匹配layouts中的middleware
  2. 匹配pages中middleware

pages和layouts中添加:

export default{
middleware:'auth'
}

如果只配置一个中间件,可以给一个字符串,同时配置多个中间件,可以给一个数组。

资源文件

  • webpack构建

默认情况下 Nuxt 使用 vue-loaderfile-loader 以及 url-loader 这几个 Webpack 加载器来处理文件的加载和引用。对于不需要通过 Webpack 处理的静态资源文件,可以放置在 static 目录中。

  1. file-loader:能让你指定从什么地方拷贝资源文件以及发布后放到哪个目录去,并能让你使用版本哈希码来重命名发布后的文件来实现增量更新和更好的缓存策略。
  2. url-loader:能根据你指定的文件大小阈值,来判断一个文件是转换成内联的base-64码(如果该文件尺寸小于该阈值)还是使用file-loader来降级处理。小文件base-64化能有效减少HTTP请求数。
  3. vue-loader: 自动使用 css-loader 和Vue模板编译器来编译处理vue文件中的样式和模板。在此编译过程中,所有的资源URL例如 <img src="...">、 background: url(...) 和 CSS中的 @import 均会被解析成模块通过 require 引用。

举个例子, 假设我们有以下文件目录结构:

-| assets/ 
----| image.png 
-| pages/ 
----| index.vue

如果我们在CSS代码中使用 url('~assets/image.png'), 那么编译后它将被转换成 require('~/assets/image.png')。 你必须在url CSS引用中使用~assets(没有斜杠)或@别名,即background:url("~assets/banner.svg")

如果在行行内样式中使用的话,需要这样写:

<img :src="require('~/assets/image.png') " />

// 或者
<div>
<img :src="imgSrc" />
</div>
export default {
  data() {
    return {
    imgSrc:'require('~/assets/image.png')'
    }}}
  • 静态文件

如果你的静态资源文件需要 Webpack 做构建编译处理,例如stylus,sass,imgges,fonts等可以放到 assets 目录,否则可以放到 static 目录中去。

Nuxt 服务器启动的时候,该目录下的文件会映射至应用的根路径 / 下,像 robots.txt 或 sitemap.xml 这种类型的文件就很适合放到 static 目录中。

你可以在代码中使用根路径 / 结合资源相对路径来引用静态资源:

// 引用 static 目录下的图片 
<img src="/my-image.png"/> 

//引用 assets 目录下经过 webpack 构建处理后的图片 
<img src="~/assets/my-image-2.png"/>