nuxt3+vite+pinia+vueuse+element plus 从零开始搭建

1,930 阅读4分钟

一、了解Nuxt

  • Nuxt是一个基于 Vue.js 的服务端渲染应用框架
  • Nuxt 3 带有稳定的、生产就绪的 API 和 50 多个由社区和 Nuxt 团队使用 Nuxt Kit 构建的支持模块

二、新特性

  • 更轻量:以现代浏览器为目标的服务器部署和客户端产物最多可缩小 75 倍
  • 更快:基于 nitro 提供动态代码分割能力,以优化冷启动性能
  • Hybrid:增量静态生成和其他的高级功能现在都成为可能
  • Suspense:在任意组件和导航前后都可以获取数据
  • Composition API:使用 Composition API 和 Nuxt 3 的 composables 实现真正的代码复用
  • Nuxt CLI:没有任何依赖,帮你轻松搭建项目和集成模块
  • Nuxt Devtools:通过直接在浏览器中查看信息和快速修复实现更快地工作
  • Nuxt Kit:具有 Typescript 和跨版本兼容性的全新模块开发
  • Webpack 5:更快的构建时间和更小的包大小,无需配置
  • Vite:使用 Vite 作为打包工具,体验闪电般快速的 HMR
  • Vue 3:Vue 3 是你下一个 Web 应用程序的坚实基础
  • TypeScript:使用原生 TypeScript 和 ESM 构建,无需额外步骤

更多新特性见官网文档

三、初始化项目

node.js => 18.14.0
npm => 9.3.1

1. 初始化项目

npx nuxi init first-nuxt-app

2. 安装依赖

cd first-nuxt-app

# yarn
yarn install

# npm
npm install

3. 运行

npm run dev

四、新建常用目录

1. 新建 app(src)目录

mkdir src

并且把 app.vue 文件移入到 src 目录下

同时修改配置文件 nuxt.config.ts

// https://nuxt.com/docs/api/configuration/nuxt-config
export default defineNuxtConfig({
  srcDir: 'src/'
})

2. 配置页面路由目录:pages

1. 新建 src/pages 目录

mkdir src/pages

2. 新建 src/pages/index.vue 首页

touch src/pages/index.vue

3. 配置 src/pages/index.vue

<template>
  <div>
    <h1>欢迎来到首页</h1>
  </div>
</template>

4. 修改 src/app.vue 入口

<template>
  <div>
    <!-- 路由出口 -->
    <NuxtPage></NuxtPage>
  </div>
</template>

3. 配置动态路由

1. 新建 src/pages/[id] 目录(目录名一定要是 [id])

mkdir src/pages/[id]

2. 新建 src/pages/[id]/index.vue 文件

<template>
  <div>
    <h1>详情页面</h1>
  </div>
</template>

3. 页面中访问:http://localhost:3000/[id]

其中 [id] 是一个动态的数字,可以是 http://localhost:3000/123,也可以是 http://localhost:3000/456

4. 新增 layouts 模板

1. 新建 src/layouts 目录

mkdir src/layouts

2. 新建 src/layouts/default.vue 默认文件

<template>
  <div>
    <h1>默认模板 可页面引入</h1>
    <slot />
  </div>
</template>

3. 在全局页面中配置: src/app.vue(也就是每个页面中都会有该模板)

<template>
  <div>
    <!-- 路由出口 -->
    <NuxtLayout>
      <NuxtPage></NuxtPage>
    </NuxtLayout>
  </div>
</template>

4. 自定义模板(类似 header、footer)

新建 src/layouts/header.vue

<template>
  <div>
    <h1>头部模板 header</h1>
  </div>
</template>

5. 使用自定义模板

<template>
  <div>
    <NuxtLayout name="header"/>
    <NuxtLink to="/11">进入详情页</NuxtLink>
  </div>
</template>

五、配置组件 components

1. 新建 src/components 目录

mkdir src/components

2. 新建 src/components/ListItem.vue 文件

<template>
  <ul>
    <li>
      <NuxtLink to="/111">111</NuxtLink>
    </li>
    <li>
      <NuxtLink to="/222">222</NuxtLink>
    </li>
    <li>
      <NuxtLink to="/333">333</NuxtLink>
    </li>
    <li>
      <NuxtLink to="/444">444</NuxtLink>
    </li>
  </ul>
</template>

3. 在 src/pages/index.vue 文件中使用

<template>
  <div>
    <h1>欢迎来到首页</h1>
    <ListItem></ListItem>
  </div>
</template>

在这里可以看到 不需要import 去导入 ListItem.vue 就可以直接使用组件

4. <ClientOnly/> 组件

Nuxt 提供了 <ClientOnly> 专门用于仅在客户端渲染组件的组件;

要仅在客户端导入组件,请在仅客户端插件中注册该组件。

<template>
  <div>
    <ClientOnly>
      <!-- 此组件仅在客户端显示 -->
      <Comments />
    </ClientOnly>
  </div>
</template>

六、配置插件 plugins

Nuxt 会自动读取 plugins 目录中的文件并在创建 Vue 应用程序时加载它们;

你可以在文件名中使用 .server 或 .client 后缀来让插件在 服务器端 或 客户端 加载插件;

1. 新建 src/plugins 目录

mkdir src/plugins

2. 以 vue 指令为例:新建 src/plugins/directives.ts 文件

export default defineNuxtPlugin((nuxtApp) => {
  nuxtApp.vueApp.directive('focus',{
    mounted (el) {
      el.focus()
    },
    getSSRProps (binding, vnode) {
      // you can provide SSR-specific props here
      return {}
    }
  })
})

七、用 composables 灵活配置 hooks

在 Nuxt 3 中使用该目录时,composables/ 目录将自动导入,将 Vue 可组合项(Hooks)自动导入到您的应用程序中,即不需要在其它地方 import

所以你如果写一些通用的 hooks,只需放入该目录下即可;

1. 新建 src/composables 目录

mkdir src/composables

2. 新建 src/composables/useFoo.ts 文件

export const useFoo = () => {
  return useState('foo', () => 'bar')
}

3. 在 src/pages/index.vue 中使用

<template>
  <div>
    <h1>欢迎来到首页</h1>
    <ListItem></ListItem>
    <h4>foo:{{ foo }}</h4>
  </div>
</template>
<script setup>
  const foo = useFoo()
</script>

根据以上操作,你可以创建属于你自己的 hooks

八、Nuxt 常用的 Hooks

1. useAppConfig

// 访问项目中的 Nuxt 配置
const appConfig = useAppConfig()
console.log(appConfig)

2. useAsyncData

// 在页面、组件和插件中,您可以使用 useAsyncData 来访问异步返回的数据
const { data, pending, error, refresh } = await useAsyncData(
  'mountains',
  () => $fetch('https://api.nuxtjs.dev/mountains')
)

3. useFetch

// 在页面、组件或者插件中可以使用 useFetch 获取任意URL资源。
// useFetch 是对 useAsyncData 包装,自动生成key同时推断响应类型,用起来更简单。
const param1 = ref('value1')
const { data, pending, error, refresh } = await useFetch('https://api.nuxtjs.dev/mountains', {
  query: { param1, param2: 'value2' }
})

4. useCookie

<template>
  <div>
    <h1>欢迎来到首页</h1>
    <ListItem></ListItem>
    <h4>foo:{{ foo }}</h4>
    <h5>counter: {{ counter }}</h5>
  </div>
</template>

<script setup>
  // 在页面、组件或者插件中可以使用 useFetch 获取任意URL资源。
  const counter = useCookie('counter')
  counter.value = 100
</script>

5. useRoute

<template>
  <div>
    <h1>欢迎来到首页</h1>
    <ListItem></ListItem>
    <h4>foo:{{ foo }}</h4>
    <h5>route_id: {{ route.params.id }}</h5>
  </div>
</template>

<script setup>
    // useRoute 是一个在实际项目开发中使用较多的 hooks,主要返回当前路由的一些数据;并且必须在 setup 函数、插件或路由中间件中调用。
    const route = useRoute()
</script>

6. useRouter

const router = useRouter()
router.back(); router.forward()
router.go()
router.push({ path: "/home" })
router.replace({ hash: "#bio" })

更多 Hooks 等相关 API 请查看官网文档

九、配置 pinia

1. 安装

npm install pinia @pinia/nuxt

2. 配置 nuxt.config.ts

// nuxt.config.ts
export default defineNuxtConfig({
    // ... 其他配置
    modules: [
        // ...
        '@pinia/nuxt',
    ],
})

3. 新建 src/stores/useUserStore.ts

import { defineStore } from "pinia";

export const useUserStore = defineStore('user', {
  state: () => ({
    name: '張三',
    age: 18,
    sex: '男'
  }),
  getters: {
    ageAdd: (state) => state.age++
  },
  actions: {
    ageChange() {
      this.age++
    }
  }
})

4. 使用

<template>
  <div>
    <h3>姓名:{{ name }}</h3>
    <h3>年齡:{{ age }}</h3>
    <h3>性別:{{ sex }}</h3>
    <el-button type="primary" @click="storeChange">单独改变值</el-button>
    <el-button type="primary" @click="storeReset">重置</el-button>
    <el-button type="primary" @click="storePatch">批量改变值</el-button>
    <el-button type="primary" @click="storeActions">調用actions方法</el-button>
  </div>
</template>

<script setup>
  import { storeToRefs } from 'pinia'
  import { useUserStore } from '~/stores/useUserStore'
  const userStore = useUserStore()
  // 结构解析
  const { name, age, sex } = storeToRefs(userStore)
  // 单独改变值
  const storeChange = () => {
    userStore.name = '李四'
  }
  // 重置值
  const storeReset = () => {
    userStore.$reset()
  }
  // 批量改变值
  const storePatch = () => {
    userStore.$patch((state) => {
      state.name = '王五'
      state.sex = '女'
    })
  }
  // 調用actions方法
  const storeActions = () => {
    userStore.ageChange()
  }
</script>

更多 Pinia 等相关 API 请查看官网文档

十、引入scss并配置全局使用

1. 安装

npm install sass --save-dev

2. 新建 src/assets/styles 目录

mkdir src/assets/styles

3. 目录下新建 default.scss 文件

$bgColor: rgb(125, 159, 172);
$theme: red;

4. 在 nuxt.config.ts 中添加 scss 的配置

export default defineNuxtConfig({
  vite: {
    css: {
      preprocessorOptions: {
        scss: {
          additionalData: '@import "@/assets/styles/default.scss";'
        }
      }
    }
  }
})

5. 使用

<style lang="scss">
body {
  background-color: $bgColor;
  color: $theme;
}
</style>

十一、配置 vueuse

1. 安装

npm install @vueuse/nuxt @vueuse/core

2. 配置 nuxt.config.ts

// nuxt.config.ts
export default defineNuxtConfig({
  // ... 其他配置
  modules: [
    // ...
    '@vueuse/nuxt'
  ]
})

3. 使用 VueUse 函数

<template>
  <div>pos: {{x}}, {{y}}</div>
</template>

<script setup lang="ts">
  // 实时获取鼠标当前的位置
  const { x, y } = useMouse()
  // 获取当前用户使用的主题
  const isDark = usePreferredDark()
  // 把数据持久化到LocalStorage本地存储中
  const storage = useLocalStorage("my-key", { foo: "bar" })
</script>

十二、配置element plus

1. 安装

npm install element-plus --save
npm install @element-plus/icons-vue

2. 配置 nuxt.config.ts

// nuxt.config.ts
export default defineNuxtConfig({
  // ... 其他配置
  css:[
    'element-plus/dist/index.css',
  ],
})

3. 新建 src/plugins/element-plus.client.ts

import * as ElementPlus from 'element-plus/dist/index.full'
import zh from 'element-plus/es/locale/lang/zh-cn'
  
export default defineNuxtPlugin((nuxtApp) => {
  nuxtApp.vueApp.use(ElementPlus, {
    locale: zh,
  })
})

4. 使用

<template>
  <div>
    <el-button>Default</el-button>
    <el-button type="primary">Primary</el-button>
    <el-button type="success">Success</el-button>
    <el-button type="info">Info</el-button>
    <el-button type="warning">Warning</el-button>
    <el-button type="danger">Danger</el-button>
  </div>
</template>