加载中...

【2024年4月】nuxt3 项目模板,让你开发官网得心应手

【2024年4月】nuxt3 项目模板,让你开发官网得心应手

本文带领大家开发一套通用的官网开发模板,名字叫 nuxt3-best,名字不重要,不是best也不重要,好用才最重要。

前言

pnpm dlx nuxi@latest init nuxt3-best

接着选择包管理器,有 npm pnpm yarn bun,我们选择 pnpm

接着会问我们是否初始化 git 仓库,选择 yes 就行了。

刚创建出来的项目目录结构非常简单,可以说只有一个 App.vue,其他都是配置文件,如下图。

New Image

默认界面如下:

New Image

接下来开始开整项目,大概有以下几个步骤:

  • 一、基本配置 prettiersrc目录.npmrc
  • 二、引入 nuxt-ui (可选)
  • 三、引入 tailwindcss/unocss
  • 四、整理布局
  • 五、响应式布局
  • 六、表单验证
  • 七、路由和导航
  • 八、数据获取
  • 九、引入其他常用 moduls
  • 十、打包部署

鉴于 unibest 太强的代码格式配置,招到很多程序员的不适应,这个 nuxt3-best 项目就温和一点了。另外,官网作为短时间就完成的项目(且大概率是一个人完成)来说,我们不做过多限制,只配个 prettier 就行了。

一、基本配置 prettiersrc目录

    1. .prettierrc.cjs 文件编写如下代码
js
复制代码
// @see https://prettier.io/docs/en/options module.exports = { singleQuote: true, tabWidth: 2, printWidth: 100, useTabs: false, semi: false, trailingComma: ''all'', endOfLine: ''auto'', htmlWhitespaceSensitivity: ''ignore'', overrides: [ { files: ''*.json'', options: { trailingComma: ''none'', }, }, ], }
    1. src目录

因为 Nuxt3 项目默认的文件夹都在顶层,就像 HBuilderX 创建的 Uniapp 项目那种的,全部在顶层,感觉很乱,所以推荐把所有的源代码都放到 src 里面,并增加 1个 配置即可。

New Image

上图是全部在顶层的图,把这些统统放到 src 里面,包括 App.vue 也要放进去。接着,在 nuxt.config.ts 中加上 srcDir 的配置:

diff
复制代码
// https://nuxt.com/docs/api/configuration/nuxt-config export default defineNuxtConfig({ devtools: { enabled: true }, + // https://nuxt.com/docs/api/nuxt-config#srcdir + srcDir: ''src/'', })

New Image

  • 3. .npmrc 文件编写如下代码

这样就可以使用 淘宝源 和使用 pnpm 安装依赖了。

text
复制代码
shamefully-hoist=true strict-peer-dependencies=false registry=https://registry.npmmirror.com/

引入 nuxt-ui ( 可选 )

大部分官网开发,不需要引入第三方 UI 库,页面内容基本都是自己手写,包括组件。但是耐不住时不时有下拉框、表单和表单验证等功能出现,这个时候自己手写就太花时间了,还是引入第三方 UI库 吧。

我司官网有一个页面,需要用户留下信息,需要表单,于是我就引入了 nuxt-ui,主要是用它的表单。为啥不选其他 UI 库,2个原因:1)够用就行,2)nuxt 官方维护的。

怎么引入呢?

nuxt.com/modules 有很多官方维护的 modules,可以非常方便地集成,如下图:

New Image

选好 ui 那个卡片,点击进去,进入 nuxt-ui 文档,如下图只需要 2步 就引入了:

New Image

经过我的实际操作,这里使用 npx 安装会有问题,所以不能执行 npx nuxi@latest module add ui,要改为 pnpm add @nuxt/ui

sh
复制代码
# npx nuxi@latest module add ui 不可以,因为原来是 pnpm 安装的,与npx 不兼容。 pnpm add @nuxt/ui

接着把 @nuxt/ui 加到 modules,如下:

diff
复制代码
// https://nuxt.com/docs/api/configuration/nuxt-config export default defineNuxtConfig({ devtools: { enabled: true }, // https://nuxt.com/docs/api/nuxt-config#srcdir serverDir: ''src/'', + modules: [''@nuxt/ui''], })

注意,nuxt-ui 内部已经引入了 tailwindcss,所以无需另外引入 原子化CSS 了,你看下面的效果:

New Image

三、引入 tailwindcss/unocss

如果引入了 nuxt-ui 则本节可以跳过,nuxt-ui 自带 tailwindcss

如果需要引入 原子化CSS,则我推荐 UnoCSSmodules 找到 UnoCSS,如下图:

New Image

引入方式如下:

New Image

对应代码如下:

  • pnpm add -D @unocss/nuxt
  • nuxt.config.ts
ts
复制代码
// nuxt.config.ts export default defineNuxtConfig({ modules: [ ''@unocss/nuxt'', ], })
  • uno.config.ts
ts
复制代码
// uno.config.ts import { defineConfig } from ''unocss'' export default defineConfig({ // ...UnoCSS options })

四、整理布局

开发 layoutspages ,并对 layouts/default.vue 进行布局,要的效果就是:

  • 顶部栏固定在顶部
  • 中间是内容区域
  • footbar 一直在”底部“,当内容不足一屏的时候,固定在底部,超过一屏的时候,跟随内容在最底部。

layouts/default.vue 代码如下:

html
复制代码
<template> <div class="flex flex-col h-screen"> <div class="leading-10 bg-slate-500 fixed w-full z-20 h-10">topbar</div> <div class="flex-1 pt-10 bg-gray-100"> <slot /> </div> <div class="h-10 leading-10 bg-slate-500">footer</div> </div> </template>

五、响应式布局

    1. 内置的 .container

不管是古老的 BootStrap 还是现代的 tailwindcss/unocss,都对 .container 进行了响应式处理,官网开发经常用得到。

举个例子,官网经常在最上面来个左右通屏的图片,下面内容又是左右居中的内容区域,我通常会这样处理:

html
复制代码
<template> <div> <img class="w-full" src="~/assets/images/pretty-girl.png" /> <div class="container m-auto bg-yellow-100 p-4"> <fg-content :line="40" /> </div> </div> </template>

效果如下:

New Image

    1. 自己写响应式,如 grid grid-cols-1 lg:grid-cols-2 2xl:grid-cols-3 gap-4,这个比较直观,就不演示了。

六、表单验证

talk is cheap, show me the code

下面用到了 zod,记得 pnpm add zod 一下。

vue
复制代码
<script setup lang="ts"> import { z } from ''zod'' import type { FormSubmitEvent } from ''#ui/types'' const options = [ { label: ''Option 1'', value: ''option-1'' }, { label: ''Option 2'', value: ''option-2'' }, { label: ''Option 3'', value: ''option-3'' }, ] const state = reactive({ input: undefined, inputMenu: undefined, textarea: undefined, select: undefined, selectMenu: undefined, checkbox: undefined, toggle: undefined, radio: undefined, radioGroup: undefined, switch: undefined, range: undefined, }) const schema = z.object({ input: z.string().min(10), inputMenu: z.any().refine((option) => option?.value === ''option-2'', { message: ''Select Option 2'', }), textarea: z.string().min(10), select: z.string().refine((value) => value === ''option-2'', { message: ''Select Option 2'', }), selectMenu: z.any().refine((option) => option?.value === ''option-2'', { message: ''Select Option 2'', }), toggle: z.boolean().refine((value) => value === true, { message: ''Toggle me'', }), checkbox: z.boolean().refine((value) => value === true, { message: ''Check me'', }), radio: z.string().refine((value) => value === ''option-2'', { message: ''Select Option 2'', }), radioGroup: z.string().refine((value) => value === ''option-2'', { message: ''Select Option 2'', }), range: z.number().max(20, { message: ''Must be less than 20'' }), }) type Schema = z.infer<typeof schema> const form = ref() async function onSubmit(event: FormSubmitEvent<Schema>) { // Do something with event.data console.log(event.data) } </script> <template> <UForm ref="form" :schema="schema" :state="state" @submit="onSubmit" > <UFormGroup name="input" label="Input"> <UInput v-model="state.input" /> </UFormGroup> <UFormGroup name="inputMenu" label="Input Menu"> <UInputMenu v-model="state.inputMenu" :options="options" /> </UFormGroup> <UFormGroup name="textarea" label="Textarea"> <UTextarea v-model="state.textarea" /> </UFormGroup> <UFormGroup name="select" label="Select"> <USelect v-model="state.select" placeholder="Select..." :options="options" /> </UFormGroup> <UFormGroup name="selectMenu" label="Select Menu"> <USelectMenu v-model="state.selectMenu" placeholder="Select..." :options="options" /> </UFormGroup> <UFormGroup name="toggle" label="Toggle"> <UToggle v-model="state.toggle" /> </UFormGroup> <UFormGroup name="checkbox" label="Checkbox"> <UCheckbox v-model="state.checkbox" label="Check me" /> </UFormGroup> <UFormGroup name="radioGroup" label="Radio Group"> <URadioGroup v-model="state.radioGroup" :options="options" /> </UFormGroup> <UFormGroup name="radio" label="Radio"> <URadio v-for="option in options" :key="option.value" v-model="state.radio" v-bind="option" > {{ option.label }} </URadio> </UFormGroup> <UFormGroup name="range" label="Range"> <URange v-model="state.range" /> </UFormGroup> <UButton type="submit">Submit</UButton> <UButton variant="outline" @click="form.clear()"> Clear </UButton> </UForm> </template>

效果如下:(提交不满足规范,会报红)

New Image

如果一行要放2个表单怎么办?

diff
复制代码
+<div > <UFormGroup name="input" label="Input"> <UInput v-model="state.input" /> </UFormGroup> <UFormGroup name="inputMenu" label="Input Menu"> <UInputMenu v-model="state.inputMenu" :options="options" /> </UFormGroup> +</div>

效果如下:

New Image

七、路由和导航

首先申明,

  1. 常用的API都是自动导入的,无需引入。

  2. 约定的几个文件夹里面的东西都是可以直接使用的,无需引入。

可以直接通过 const route = useRoute() 拿到 route 页面路由信息,通过它可以获取路由 queryparams

  • 1) http://localhost:3000?name=fg&age=30

const { name, age } = route.query 可以拿到 nameage 信息。

  • 2) http://localhost:3000/product/5

某个路由导航到这里,那么就可以命中 src/pages/product/[pId].vue 页面,页面里面可以通过如下代码获取到 pId

const { pId } = route.params 可以拿到 pId 信息。

    1. 路由导航,有2种方式,如下

    • <NuxtLink to="/product/5" > 进入详情 </NuxtLink
    • 使用编程方式导航,const router = useRouter() 拿到路由示例,然后 router.push("/product/5")

八、数据获取

这个直接看官网就行了,nuxt.com/docs/gettin…

主要有三种方式:useFetchuseAsyncData and $fetch

九、引入其他常用 moduls

大家可以在 nuxt.com/modules 找自己想要的

New Image

很多人官网不需要用户登录,所以 pinia 不是通用的,vueuse 倒是比较通用,还有 image 也不错,所以我就安装了这2个

sh
复制代码
pnpm add @vueuse/nuxt @nuxt/image

然后加到 nuxt.config.tsmodules 配置里,到此已经有 3个 了: modules: [''@nuxt/ui'', ''@vueuse/nuxt'', ''@nuxt/image''],.

十、打包部署

执行 pnpm build 即可完成打包,然后在服务器上运行如下命令 node .output/server/index.mjs 即可,如下图:

New Image

为了保证程序运行更加稳健,我们通常会使用 PM2nuxt.com/docs/gettin…

需要配置 ecosystem.config.cjs,内容如下:

js
复制代码
module.exports = { apps: [ { name: ''NuxtAppName'', port: ''3000'', exec_mode: ''cluster'', instances: ''max'', script: ''./.output/server/index.mjs'' } ] }

在服务器上,安装 PM2npm i -g pm2

然后运行 PM2pm2 start ecosystem.config.cjs

New Image

可以看到运行了 10cluster,应用名为 NuxtAppName

其他常用命令如:pm2 stop NuxtAppNamepm2 reload NuxtAppName

New Image

New Image


至此,完结~

总结

总结一下本文,主要描述了如何生成一个 nuxt3 项目模板,有以下 十个 步骤:

  • 一、基本配置 prettiersrc目录.npmrc
  • 二、引入 nuxt-ui (可选)
  • 三、引入 tailwindcss/unocss
  • 四、整理布局
  • 五、响应式布局
  • 六、表单验证
  • 七、路由和导航
  • 八、数据获取
  • 九、引入其他常用 moduls
  • 十、打包部署

模板地址:github.com/codercup/nu…

全文完~