nuxt3 学习及基本使用

159 阅读4分钟

1.安装

  • Node 版本要求 Node.js - v18.0.0 or newer
# 创建一个新项目

npx nuxi@latest init <project-name>

or 

pnpm dlx nuxi@latest init <project-name>

or 

bunx nuxi@latest init <project-name>

2.配置

# 配置文件
export default defineNuxtConfig({
  // My Nuxt config
})

2.1views

  • 根据/pages/中文件目录结构生成路由
# 入口文件 
app.vue

2.2Components

# 组件放在目录 components/,这些组件可以被用在页面和其他组件中,
以往我们使用这些组件需要导入并注册它们,
但Nuxt会自动导入`components/`目录中的任意组件


  • 组件名称约定

没有嵌套的组件会以文件名直接导入,但如果存在嵌套关系哪?例如下面的路径:

| components/
--| base/
----| foo/
------| Button.vue

那么组件名称将会基于路径和文件名连起来,比如上面的base/foo/Button.vue注册名称将会是BaseFooButton,将来用起来会像下面这样:

<BaseFooButton />

2.3Assets

静态资源

# 如果使用的图片文件在 public/img/目录:

<img src="/img/nuxt.png" alt="Discover Nuxt 3" />

# 如果使用的图片文件在 assets/目录:

<img src="~/assets/img/nuxt.png" alt="Discover Nuxt 3" />


2.4全局样式配置


export default defineNuxtConfig({
  vite: {
    css: {
      preprocessorOptions: {
        scss: {
          additionalData: '@use "~/assets/_colors.scss" as *;'
        }
      }
    }
  }
})

2.5导入样式文件在组件中

<script>
// Use a static import for server-side compatibility
import '~/assets/css/first.css'

// Caution: Dynamic imports are not server-side compatible
import('~/assets/css/first.css')
</script>

<style>
@import url("~/assets/css/second.css");
</style>

2.6在配置文件中使用css

export default defineNuxtConfig({
  css: ['~/assets/css/main.css']
})

2.7使用外部样式

export default defineNuxtConfig({
  app: {
    head: {
      link: [{ rel: 'stylesheet', href: 'https://cdnjs.cloudflare.com/ajax/libs/animate.css/4.1.1/animate.min.css' }]
    }
}})

2.8动态添加

useHead({
  link: [{ rel: 'stylesheet', href: 'https://cdnjs.cloudflare.com/ajax/libs/animate.css/4.1.1/animate.min.css' }]
})

2.9组件内使用

<script setup lang="ts">
const activeColor = ref('red')
const fontSize = ref(30)
const styleObject = reactive({ color: 'red', fontSize: '13px' })
</script>

<template>
  <div :style="{ color: activeColor, fontSize: fontSize + 'px' }"></div>
  <div :style="[baseStyles, overridingStyles]"></div>
  <div :style="styleObject"></div>
</template>

3.Routing

通过useRoute()获取路由信息


<script setup lang="ts">
const route = useRoute()

// When accessing /posts/1, route.params.id will be 1
console.log(route.params.id)
</script>

  • 目录
| pages/
---| about.vue
---| index.vue
---| posts/
-----| [id].vue

  • 路由参数校验
<script setup lang="ts">
definePageMeta({
  validate: async (route) => {
    // Check if the id is made up of digits
    return /^\d+$/.test(route.params.id)
  }
})
</script>

  • 动态路由

如果我们在文件名或者文件夹名称里面包含了`方括号`,它们将被转换为`动态路由`参数。

比如:


-| pages/
---| users-[group]/
-----| [id].vue


通过 `/users-admins/123` 导航即可:
  • 嵌套路由

比如下面目录结构:

-| pages/
---| parent/
------| child.vue
---| parent.vue

child.vue

<template>
  <div>
    <h1>child page</h1>
  </div>
</template>

父组件中使用NuxtChild组件显示嵌套子组件内容,parent.vue:

<template>
  <div>
    <h1>parent page</h1>
    <!-- 子组件出口 -->
    <NuxtChild></NuxtChild>
  </div>
</template>

试一下,index.vue

<NuxtLink to="/parent/child">Parent</NuxtLink>

4.fetch

数据请求:useFetchuseAsyncData、 $fetch

useFetch

<script setup lang="ts">
const { data: count } = await useFetch('/api/count')
</script>

<template>
  Page visits: {{ count }}
</template>

-------------------------
<script setup lang="ts">
const { pending, data: posts } = useFetch('/api/posts', {
  lazy: true
})
</script>

<template>
  <!-- you will need to handle a loading state -->
  <div v-if="pending">
    Loading ...
  </div>
  <div v-else>
    <div v-for="post in posts">
      <!-- do something -->
    </div>
  </div>
</template>


4.1$fetch

const users = await $fetch('/api/users').catch((error) => error.data)

4.2useAsyncData

const id = ref(1)

const { data, error } = await useAsyncData(`user:${id.value}`, () => {
  return myGetFunction('users', { id: id.value })
})

也可以使用 useLazyFetchand useLazyAsyncData

5.环境变量配置

5.1 env

# 新建两个文件
.env.development
.env.production


//package.json 
"dev": "nuxt dev --dotenv .env.development", 
"build": "nuxt build --dotenv .env.production",



//nuxt.config.ts
 // 添加运行时配置
runtimeConfig: {
   apiSecret: process.env.NUXT_API_SECRET,
   public: {
     apiBase: process.env.NUXT_PUBLIC_API_BASE || SERVER_BASE_API,
   }
}
---------------------------------------------------------------------
// 如果存在跨域
nitro: {
   devProxy: {
     '/api': {
       target: process.env.NUXT_PUBLIC_API_BASE,
       changeOrigin: true,
     }
   }
 }

6.自动导入和调试

不用import可以直接使用 vue3 的api,例如:

ref和 computed

<script setup lang="ts">
const count = ref(1) // ref is auto-imported
</script>

[components/], [composables/] and [utils/]这几个目录中的会自动导入

  • 不想自动导入:nuxt.config.ts
export default defineNuxtConfig({
  imports: {
    autoImport: false
  }
})

添加 nuxt 模块-nuxt.config.ts

export default defineNuxtConfig({
  modules: [
    // Using package name (recommended usage)
    '@nuxtjs/example',

    // Load a local module
    './modules/example',

    // Add module with inline-options
    ['./modules/example', { token: '123' }]

    // Inline module definition
    async (inlineOptions, nuxt) => { }
  ]
})

调试配置

{
  // Use IntelliSense to learn about possible attributes.
  // Hover to view descriptions of existing attributes.
  "version": "0.2.0",
  "configurations": [
    {
      "type": "chrome",
      "request": "launch",
      "name": "client: chrome",
      "url": "http://localhost:3000",
      "webRoot": "${workspaceFolder}"
    },
    {
      "type": "node",
      "request": "launch",
      "name": "server: nuxt",
      "outputCapture": "std",
      "program": "${workspaceFolder}/node_modules/nuxi/bin/nuxi.mjs",
      "args": [
        "dev"
      ],
    }
  ],
  "compounds": [
    {
      "name": "fullstack: nuxt",
      "configurations": [
        "server: nuxt",
        "client: chrome"
      ]
    }
  ]
}

7.数据请求

建议在获取组件数据时使用useFetchuseAsyncData + $fetch来防止重复获取数据。

服务器路由

~/server/api目录中的文件会自动在其路由中添加/api前缀。

要添加没有/api前缀的服务器路由,请将它们放入~/server/routes目录中。

服务器中间件

Nuxt会自动读取~/server/middleware目录中的任何文件,以创建项目的服务器中间件。

中间件处理程序将在任何其他服务器路由之前在每个请求上运行,以添加或检查标头、记录请求或扩展事件的请求对象。

中间件处理程序不应返回任何内容(也不应关闭或响应请求),只能检查或扩展请求上下文或抛出错误

  • server/middleware/log.ts
export default defineEventHandler((event) => {
  console.log('New request: ' + getRequestURL(event))
})

  • server/middleware/auth.ts
export default defineEventHandler((event) => {
  event.context.auth = { user: 123 }
})

匹配HTTP方法

处理文件名可以使用.get.post.put.delete等后缀来匹配请求的HTTP方法

server/api/test.get.ts

export default defineEventHandler(() => 'Test get handler')

server/api/test.post.ts

export default defineEventHandler(() => 'Test post handler')

在上面的示例中,使用以下方式获取/test

  • GET方法:返回Test get handler
  • POST方法:返回Test post handler

封装请求

  • 新建request.ts文件,用于编写封装代码

我选择在composables目录中新建request.tscomposables是官方默认的插件目录,官方描述:Nuxt 3使用composables/目录使用auto-imports自动将Vue组合导入到应用中!

$fetch 重复发送请求问题

const res = await useFetch('/api/hospital/list', { method: 'POST', body: filterData, watch: false });

server/api内使用

  • defineEventHandler

使用 defineEventHandler 可以让我们更方便地定义和管理这些事件处理器函数。它接收两个参数:

  • logic: 这是一个函数,用于定义事件处理器的逻辑。该函数接收一个参数,也就是事件对象(例如鼠标点击事件的 event 对象)。在该函数中,我们可以根据传入的参数执行相应的逻辑,然后返回一个结果(如 promise 或其他数据)。
  • options: 这是一个可选的参数对象,用于配置该事件处理器函数的行为。它可以包含以下属性:
    • once: 如果该属性为 true,则该事件处理器函数只会执行一次。默认值为 false。
    • defer: 如果该属性为 true,则该事件处理器函数将在下一轮事件循环中执行。默认值为 false。
export default defineEventHandler((event) => {
  const pramObj = getQuery(event) as FilterObj
  return fetchHospital(pramObj)
})

使用elementplus分页器文案中文

其中layout用来指定分页元件的布局,即定义展示的分页元件及其展示顺序,元件定义如下:

    prev:上一页的按钮。
    pager:页码列表。
    next:下一页的按钮。
    jumper:跳转到。
    total:数据总条数。
    sizes:每页显示的数据条数/分页大小。
    ->:该元件将其右侧的元件包裹起来,整体靠右对齐。
    slot: 额外自定义内容插槽。

其中,各元件用逗号分隔。

layout的值的顺序决定了元件显示的位置,比如:

    layout="total,prev, pager, next,->,jumper,sizes"

这个设置的分页组件元件将按照layout顺序布局

import { ElConfigProvider } from 'element-plus'

import zhCn from 'element-plus/dist/locale/zh-cn.mjs'
const locale = zhCn


<el-config-provider :locale="locale">
    <el-pagination
      v-model:current-page="resultData.pageNo"
      v-model:page-size="resultData.pageSize"
      :page-sizes="[10, 20, 30, 40]"
      :disabled="disabled"
      background
      layout="total, prev, pager, next, sizes, jumper"
      :total="400"
      @size-change="handleSizeChange"
      @current-change="handleCurrentChange"
    />
  </el-config-provider>

遇到的问题

1.使用pnpm install后运行报错

__vite_ssr_import_2__.createMemoryHistory is not a function


后面使用npm install

2.npm i 报错依赖版本不一致时处理

image.png

npm install --legacy-peer-deps

参考