Nuxt.js 备忘单

2025-05-24

Nuxt.js 备忘单

Nuxt.js 的存在是为了让你的生活更轻松,它也能使 Vue.js 的开发流程更加流畅。然而,尽管它有很多优点,但它也有一些怪癖,会让你忍不住点击 Google 上的每一个链接。

本文旨在避免这些情况,它将涵盖一些常见用例和一些边缘情况,并提供一些快速简便的代码片段。本文不会对这些内容进行过于详细的阐述,但会提供必要的文档,以备不时之需。

注意:您需要充分掌握 Vue.js 概念才能充分利用本文!

在我们讨论具体内容之前,让我先解释一下什么是 Nuxt.js。

什么是 Nuxt.js?

Nuxt.js 是一个基于Vue.js的框架,允许您构建功能齐全的服务器渲染应用程序。

它开箱即用,包含大量有用的软件包:

  • 💻Vue
  • ↩️ Vue Router(用于轻松路由)
  • 💾 Vuex(用于轻松的状态管理)
  • 🏎 Vue 服务器渲染器(用于开箱即用的服务器端渲染)
  • 🕵️‍♂️ Vue 元(用于 SEO)

以下是我们将要介绍的内容列表(如果您要搜索特定内容,请随时回到这里):

一般的

路由

状态管理

搜索引擎优化

各种各样的

如果您有任何其他要求或想要添加任何新内容,请随时在 Twitter 上联系我@christo_kade

创建 Nuxt.js 项目

yarn create nuxt-app <project-name>
Enter fullscreen mode Exit fullscreen mode

这将提示您回答一些问题,包括:

  • 在集成的服务器端框架之间进行选择(默认无、Express、Koa 等)
  • 选择要安装的功能(PWA 支持、Linter / Formatter、Prettier、Axios)
  • 选择您最喜欢的 UI 框架(默认无,Bootstrap、Vuetify、Bulma 等)
  • 选择您最喜欢的测试框架(None、Jest、AVA)
  • 您想要的 Nuxt 模式(通用或 SPA,更多信息

完成后,您的依赖项就安装好了:

$ cd <project-name>
$ yarn dev
Enter fullscreen mode Exit fullscreen mode

文档

使用 Nuxt.js 进行测试

大部分测试语法取决于项目创建时选择的测试框架。Nuxt

开箱即用,@vue/test-utils通过诸如mount()shallowMount()和 等多种方法,使用该包来渲染组件render()。之后,您将能够测试特定值是否已显示、特定方法是否被调用等等。

Nuxt 还将确保为您设置好一切,您所要做的就是创建您的*.spec.js*.test.js文件并运行yarn test命令。

以下是 Nuxt 项目中 Vue 组件单元测试的经典(且简短)示例:

import { shallowMount } from "@vue/test-utils"
import cmp from "~/components/navbar/navbar"

// Mocking an icon displayed in my navbar
jest.mock("~/static/icons/svg/icon-menu.svg", () => "")

describe("Navbar component", () => {

  // We shallow mount the component while mocking some internal elements
  // Most of the time, you'll have to mock context objects such as $store or $route in order to render your component whithout any errors
  const wrapper = shallowMount(cmp, {
    // Stubbing nuxt-links in the navbar
    stubs: ["nuxt-link"],
    mocks: {
      "nuxt-Link": true,
      // Mocking the $store context object
      $store: {
        state: {
          locale: "en",
        },
      },
      // Mocking the $route context object
      $route: {
        path: "mockedPath",
      },
    },    
  })

  it("Snapshot testing", () => {
    expect(wrapper.html()).toMatchSnapshot()
  })

  describe("Components validation", () => {
    it("should return a valid component", () => {
      expect(wrapper.is(cmp)).toBe(true)
    })
  })

  describe("Content validation", () => {
    it("should render the link's name", () => {
      expect(wrapper.html()).toContain("About")
    })

    // ...
  })
})
Enter fullscreen mode Exit fullscreen mode

文档

创建新路线

在该/pages文件夹中,创建一个文件,其名称将是路线的名称。

例如:

// /pages/about.vue

<template>
  <main>
    <h1>About page</h1>
  <main/>
</template>

<script>
export default {}
</script>

<style></style>
Enter fullscreen mode Exit fullscreen mode

导航至localhost:3000/about将显示此组件的内容

文档

创建动态路线

/pages文件夹中,创建一个目录和一个以下划线为前缀的文件。

例如以下文件树:

pages/
--| users/
-----| _id.vue
--| index.vue
Enter fullscreen mode Exit fullscreen mode

.nuxt每当您构建项目时,都会在文件夹内自动生成以下路由器:

router: {
  routes: [
    {
      name: 'index',
      path: '/',
      component: 'pages/index.vue'
    },
    {
      name: 'users-id',
      path: '/users/:id?',
      component: 'pages/users/_id.vue'
    },
  ]
}
Enter fullscreen mode Exit fullscreen mode

现在您可以导航到/users/:id,并将id其设置为您需要的任何值。

要在组件中检索此值_id.vue,只需执行以下操作:

// $route is a Nuxt context object, more info: https://nuxtjs.org/api/context
const { id } = this.$route.params
Enter fullscreen mode Exit fullscreen mode

文档,包括嵌套路由和动态嵌套路由。

导航到组件模板中的路由

在任何组件内部:

// /components/example.vue

// Clicking on this nuxt-link will navigate to the /pages/about.vue component
// nuxt-link renders an <a> tag in your HTML
<template>
  <section>    
    <nuxt-link to="/about">
      About
    </nuxt-link>
  </section>
</template>

// ...
Enter fullscreen mode Exit fullscreen mode

文档

通过编程方式导航至路线

// Will add a history entry to the stack
this.$router.push({
  path: '/about'
})

// Will not
this.$router.replace({
  path: '/about'
})

// Goes back one record
this.$router.go(-1)
Enter fullscreen mode Exit fullscreen mode

创建新的商店模块

文件夹中/store,每个文件都是一个 Vuex 模块。

// /store/todos.js
export const state = () => ({
  list: []
})

export const mutations = {
  add(state, text) {
    state.list.push({
      text: text,
      done: false
    })
  },
  remove(state, { todo }) {
    state.list.splice(state.list.indexOf(todo), 1)
  },
  toggle(state, todo) {
    todo.done = !todo.done
  }
}
Enter fullscreen mode Exit fullscreen mode

现在可以使用上下文对象获取每个模块的突变、动作和状态$store

// /components/todo.vue
<template>
  <ul>
    <li v-for="todo in todos">
      <input type="checkbox" :checked="todo.done" @change="toggle(todo)">
      <span>{{ todo.text }}</span>
    </li>
    <li><input placeholder="What needs to be done?" @keyup.enter="addTodo"></li>
  </ul>
</template>

<script>
import { mapMutations } from 'vuex'

export default {
  computed: {
    todos () {
      return this.$store.state.todos.list // highlight-line
    }
  },
  methods: {
    addTodo (e) {
      this.$store.commit('todos/add', e.target.value) // highlight-line
      e.target.value = ''
    },
    ...mapMutations({ // highlight-line
      toggle: 'todos/toggle' // highlight-line
    }) // highlight-line
  }
}
</script>
Enter fullscreen mode Exit fullscreen mode

文档

在渲染组件之前更新 store

有时您需要在渲染组件之前填充给定的状态变量,方法如下:

// In any component

export default {
  // Called before rendering the component
  fetch ({ store, params }) {
    return axios.get('https://dog.ceo/api/breeds/image/random')
    .then((res) => {
      store.commit('setDog', res.data.message)
    })
  }
}
Enter fullscreen mode Exit fullscreen mode

警告:您无法通过this内部获取访问组件实例,因为它是在启动组件之前调用的(阅读更多)。

文档

动态更改页面的 head 属性

出于 SEO 目的,定义页面标题、描述关键词等会很有用。以下是如何通过编程实现的:

// In any component
export default {
  head: {
    title: 'Page title',
    meta: [
      { 
        hid: 'description', name: 'description', 
        content: 'Page description' 
      }
    ],
    // ...
  }
}
Enter fullscreen mode Exit fullscreen mode

信息:为避免在子组件中使用重复的元标记,请使用 hid 键为元元素设置唯一标识符(阅读更多)。

文档

动态路由的 SSR

运行时nuxt generate,默认情况下不会生成动态路线的 HTML 文件。

例如,如果您有一个about.vue页面和一个_id.vue,当运行时nuxt generate,生成的dist文件夹将包含/about/index.html但不会为您的动态生成任何内容_id.vue

这可能会导致您的动态路线被爬虫错过,从而不会被搜索引擎引用!

自动生成它们的方法如下:

// nuxt.config.js

module.exports = {
  // ...

  // dynamicRoutes could be a JSON file containing your dynamic routes
  // or could be retrieved automatically based on the content of your /pages folder
  generate: {
    routes: () => {
      return dynamicRoutes.map(route => `/articles/${route}`)
    },
  },

  // ...
}
Enter fullscreen mode Exit fullscreen mode

nuxt generate现在将为该generate属性返回的每个动态路由生成 HTML 文件。

文档

在整个应用中显示固定组件

有时您需要添加一个导航栏或页脚,无论当前路线如何都会显示。

默认情况下,有一个/layout文件夹包含以下内容default.vue。此布局包含<nuxt/>负责渲染每个页面内容的组件(请参阅创建新路由)。

只需修改该组件以满足您的需要,例如:

<template>
  <div>
    <navbar/>
    <nuxt/>
    <footer/>
  </div>
</template>

<script>
import navbar from "~/components/navbar/navbar"
import footer from "~/components/footer/footer"

export default {
  components: {
    cmpNavbar,    
    cmpFooter,
  },  
}
</script>
Enter fullscreen mode Exit fullscreen mode

文档

更改项目的路由器基础

在某些情况下,例如当您在 下的 Github Pages 上部署项目时username/my-project,您需要更改项目的路由器基础,以便正确显示您的资产。

// nuxt.config.js

// Will change the router base to /my-project/ when DEPLOY_ENV equals GH_PAGES
const routerBase = process.env.DEPLOY_ENV === "GH_PAGES"
  ? {
    router: {
      base: "/my-project/",
    },
  }
  : {
    router: {
      base: "/",
    },
  }

module.exports = {  
  // ...
  routerBase,
  // ...
}
Enter fullscreen mode Exit fullscreen mode

并且不要忘记更改您的package.json设置,以便nuxt.config.js知道何时为 Github Pages 构建或生成。

// package.json

"scripts": {
  "build:gh-pages": "DEPLOY_ENV=GH_PAGES nuxt build",
  "generate:gh-pages": "DEPLOY_ENV=GH_PAGES nuxt generate"
},
Enter fullscreen mode Exit fullscreen mode

处理国际化(i18n)

从运行开始yarn add vue-i18n

创建以下文件:

// /plugins/i18n.js

import Vue from "vue"
import VueI18n from "vue-i18n"

Vue.use(VueI18n)

export default ({ app, store }) => {

  // Set i18n instance on app
  // This way we can use it globally in our components
  app.i18n = new VueI18n({
    locale: store.state.locale,
    fallbackLocale: "fr",
    messages: {
      // Add the supported languages here AND their associated content files
      en: require("~/static/json/data-en.json"),
      fr: require("~/static/json/data-fr.json"),      
    },
  })
}
Enter fullscreen mode Exit fullscreen mode

并在您的中添加以下行nuxt.config.js以告知它我们正在使用该插件:

module.exports = {
  // ...
  plugins: ["~/plugins/i18n.js"],
  // ...
}
Enter fullscreen mode Exit fullscreen mode

在此示例中,当前语言环境基于我的商店的内容,如下所示:

export const state = () => ({
  locales: ["en", "fr"],
  locale: "fr",
})

export const mutations = {
  setLanguage(state, locale) {
    if (state.locales.indexOf(locale) !== -1) {
      state.locale = locale
    }
  },
}
Enter fullscreen mode Exit fullscreen mode

因此,无论何时调用setLanguage,语言环境都会自动更新,并且会加载正确的 JSON 文件!✨

您的文件内容现在可以在整个应用程序中使用,如下所示:

// Here we access the 'users' array in our JSON file
this.$t("users")
Enter fullscreen mode Exit fullscreen mode

文档

将字体导入到你的项目中

// nuxt.config.js

module.exports = {
  /*
   ** Headers of the page
   */
  head: {    
    // ...
    link: [
      {
        rel: "stylesheet",
        href: "https://fonts.googleapis.com/css?family=Lato",
      },
    ],
  },

  // ...
}
Enter fullscreen mode Exit fullscreen mode

总结

好了,我想一篇文章就够了。我已经介绍了很多用例,希望对你们中的一些人有用。

如果你有任何疑问或想补充内容,欢迎在 Twitter 上给我留言@christo_kade,也请关注我,以便及时了解我撰写的新文章或与 JavaScript 和 CSS 相关的有趣发现 😄

文章来源:https://dev.to/christopherkade/nuxt-js-cheat-sheet-4513
PREV
Async/await 的危险
NEXT
改善你的 Git 工作流程