🚀 用 Nuxt3 打造公司官网:一场从 0 到 1 的实战冒险

🤷‍♂️ 为什么要自己写个官网?

俗话说:"人靠衣装,佛靠金装,公司靠官网装。"

官网是公司的门面,就像是 名片 + 海报 + 展厅 的三合一。

如果官网掉链子,那就像穿着拖鞋去相亲------第一印象直接减分。

我们公司之前的官网,是几年前外包团队做的:

  • 技术栈老得能当"古董";
  • UI 风格满满的 2015 味儿
  • 响应式体验勉强凑合,性能还常常"慢半拍";
  • 更要命的是:每次想加个新功能,都得像修老爷车一样,拧半天螺丝,还不一定能启动。

所以,经过自我的灵魂拷问,最终决定: 👉 "自己动手,丰衣足食"

⚙️ 技术选型:把官网打造成"国际化大别墅"

我们的新官网为什么选 Nuxt3 ?因为它比普通 Vue3 就像 跑车比自行车 (😱💥🤯些许夸张):

  • 快得飞起:内置服务端渲染 + 静态生成,页面秒开不拖拉。
  • 搜索引擎爱它:百度、Google、Bing都抢着认它朋友。
  • 开发起来像开挂:文件路由自动生成、组合式 API、TypeScript 支持,写代码也能"飘起来"。
  • 改版不慌:组件化 + Pinia,团队协作顺畅,维护像玩积木一样轻松。

总结一句:Nuxt3 不只是盖个官网,它帮我们盖了个 智能别墅------炫酷、好用、随时升级。而之前那个老外包官网?嗯......就像老式公寓,住得了,但卡顿掉漆,让人抓狂。

这就是我们选择 Nuxt3 的理由------既要面子,也要里子,还顺便秀了点技术实力。

新官网可不是随便盖盖,我们得满足老板的"国外网站范儿"审美:大气、简洁、有格调。于是技术选型就像挑家具------要好看,还要好用:

  • 国际化支持(i18n):官网得能说多国语言,客户来自世界各地,不然国外的小伙伴看到中文界面估计直接右上角叉掉。但涉及到每个页面元素、按钮文字、提示信息等等,都需要有人去整理、翻译、校对(这是痛苦的过程,无论对于设计、还是对于开发人员);

  • TailwindCSS + Bootstrap:老板喜欢 Bootstrap 的简洁大气,我想用 Tailwind 玩出定制化风格......结果 CSS 冲突就像两只猫抢沙发,互相打架(解决方案在底部)。

  • Element Plus UI:"联系我们"模块中更青睐 Element Plus 表单的优雅交互。

    • 实际用途
      • Bootstrap:用于整体布局和国际化风格,满足老板对"国外网站大气感"的审美。
      • Element Plus:专注于表单控件和交互体验,让用户填写信息更顺畅。
    • 分析与建议
      1. 按需引入:Bootstrap 用于布局和网格,Element Plus 只在表单等必要模块引入。
      2. 避免冲突:两套 UI 样式尽量隔离,统一主题风格,避免界面割裂。
      3. 维护成本:虽然有两套 UI,但只在有限场景使用 Element Plus,维护成本可控。

总结一句:Bootstrap 是"外表帅气",Element Plus 是"功能贴心",两者组合让网站既有颜值又有体验。

  • Pinia(状态管理):严格来说不是必须,但给它留个位置,就像在客厅摆个备用沙发,什么时候需要随时派上用场。

总结一句:新官网就是一栋智能别墅,国际化大门敞开,布局漂亮,UI 风格多样,状态管理随时待命。走进来,你就知道"高级感"不是吹的。

🗂️ Nuxt3 项目结构

1. assets/

  • 存放未编译的静态资源(SASS/LESS、图片、字体)。
  • 不会直接被打包到 /public,需通过 importurl() 使用。

2. components/

  • 存放可复用的 Vue 组件。
  • Nuxt3 支持 自动导入 ,可直接使用components/下定义的组件,自动导入统一把组件名转成 PascalCase 或 kebab-case,同时支持子目录嵌套,比如components/ui/Button.vue → <UiButton /> (😅写惯了组件导入的方式,前期使用的时候都是手动导入,虽然都支持,但既然支持自动导入,尽量使用自动导入)。

3. composables/

  • 存放自定义 Composition API 函数(useXXX)。
  • 用于逻辑复用,例如 useUser()useProduct()

4. layouts/

  • 页面布局模板,例如 default.vuebootstrap.vueadmin.vueempty.vue
  • 页面可通过 definePageMeta({ layout: 'bootstrap' }) 使用不同布局。

5. middleware/

  • 页面或路由守卫逻辑,例如登录验证、权限检查。
  • 可全局或单页面使用。 📝 我们官网暂时不涉及注册登录的逻辑,可能有些公司涉及到产品购物车相关的业务,需要登录验证和权限检查

6. pages/

  • 存放路由页面,自动生成路由
  • 例如 pages/index.vue/pages/about.vue/about。 📝 Nuxt3支持动态路由,[param].vue,比如我的产品详情页目录结构是pages/products/detail/[id].vue

7. plugins/

  • 注册全局插件,如第三方库、全局组件、API 封装。
  • 可选择客户端(xxx.client.ts)、服务端(xxx.server.ts)或两者同时加载(文件名无需 .client 或 .server)。 📝 一般涉及到window、document或者动画相关的都在客户端,访问数据库、文件系统都在服务端,一些工具函数则两端都可。

8. public/

  • 放置静态资源,直接映射到网站根路径。
  • 例如 /favicon.ico/robots.txt,因为官网涉及到很多资源素材,同样也存放在该目录,如图片、视频、字体等。

9. server/

  • Nuxt3 内置服务端目录(Nitro)。
  • server/api/ → REST API 路由,例如 server/api/user.ts/api/user
  • server/plugins/ → 服务端插件,例如数据库连接、日志处理。 📝 讲道理这块我没有用到,因为我搭了一个简单的springboot的后台,直接调用api,包括联系我们的提交和获取商品的列表和明细直接通过封装的api方法去请求,看介绍说server/服务端扩展目录 ,用于自定义 API 和插件。不是必需,尤其是纯前端、静态或只依赖外部API的Nuxt3项目。只有在你需要服务端逻辑(如数据库、日志、缓存、邮件)时,才需要使用,这块有待各位进一步探索,没使用不敢妄言。

10. .nuxt/

  • Nuxt 内部生成目录,存放编译产物和自动生成代码。
  • 不需手动修改,通常加入 .gitignore

11. nuxt.config.ts

nuxt.config.ts 是 Nuxt 3 项目的核心配置文件,负责定义整个项目的全局行为和配置。主要功能包括:

功能模块 说明
🏷️ 页面信息与 HTML Head 配置网站标题、meta 信息、favicon、外部脚本等,确保 SEO 与页面基础信息完整
🎨 全局样式与 PostCSS 配置 引入全局 CSS/SCSS 文件,配置 PostCSS 插件(如 TailwindCSS、Autoprefixer)及自定义选择器前缀,统一样式规范
⚙️ 模块、插件与国际化 配置 Nuxt 模块(Tailwind、Pinia、i18n、Element Plus 等),支持国际化选项,包括语言、浏览器语言检测和消息管理
🌐 运行时环境变量 使用 runtimeConfig 管理开发与生产环境的 API 地址及公共变量,实现环境隔离和安全性
🚀 Vite 构建优化 配置 Vite 插件(如 SVG Loader)、依赖优化、代码拆分等,提高构建速度与性能
🔗 Nitro 服务端开发代理 配置 API 代理,用于本地开发环境调试后端接口,模拟服务端行为

12. package.json

  • 项目依赖与脚本。
  • 常用脚本:
    • dev:开发模式
    • build:打包
    • preview:预览

13.其它(根据个人和项目需要)

  • constants/ 存放项目常量
  • types/ typescript生命定义
  • stores/ pinia modules定义
  • utils/ 工具类和方法
  • directives/ 自定义指令(如数字滚动效果)
  • app.vue 项目入口(全局loading可以在其中实现)
  • .env .env.development .env.production\] 相关环境变量定义

  • tailwind.config.ts tailwindcss配置文件
  • tsconfig.json ts配置文件

📦 Windows 服务器部署 Nuxt3(pm2 + Node.js)

在 Windows 服务器上,我们使用 pm2 运行 Nuxt3 构建后的 .output/server/index.mjs

  • Node.js ≥ 18

  • 全局安装pm2,使用pm2管理项目

🌟 问题及解决方案

Nuxt3 数据请求封装总结

在 Nuxt3 中,useAsyncDatauseFetch$fetch 三者的区别与使用场景总结如下,掌握它们可以避免常见坑。

API 类型 SSR 支持 响应式 内部调用 适用场景
$fetch 请求工具 ✅ 可在 SSR/CSR ❌ 普通 Promise,不响应式 原生 ohmyfetch 灵活调用 API,可在服务端、插件、组合函数中使用
useAsyncData 数据获取组合式 API ✅ SSR 缓存、响应式 ✅ data/pending/error 内部可用 $fetch 获取异步数据并绑定组件,支持 SSR/客户端复用、缓存
useFetch useAsyncData 封装 ✅ 同上 ✅ 同上 内部直接调用 $fetch 简化写法,GET 请求绑定模板最常用

⚠️ 注意:useFetch 本质上是 useAsyncData(() => $fetch(...)) 的语法糖。


TailwindCSS + Bootstrap冲突
xml 复制代码
1. 在 `layouts` 中目录下定义了`bootstrap.vue`,给使用bootstrap布局的区域包一层 `.bootstrap-wrapper.bootstrap-scope`:
```vue
<template>
  <div class="bootstrap-wrapper bootstrap-scope">
    <TheHeader />
    <div class="wrapper">
      <slot />
      <TheFooter />
    </div>
  </div>
</template>
<script setup>
import TheHeader from "~/components/TheHeader.vue";
import TheFooter from "~/components/TheFooter.vue";
</script>
```
2. 配合 PostCSS 插件 `postcss-prefix-selector` 给 Bootstrap 样式加前缀,只作用于 `.bootstrap-wrapper.bootstrap-scope` 内部:
```ts
postcss: {
  plugins: {
    tailwindcss: {},
    autoprefixer: {},
    "postcss-prefix-selector": {
      prefix: ".bootstrap-wrapper.bootstrap-scope",
      transform(prefix: string, selector: string, prefixedSelector: string): string {
        if (selector === "html" || selector === "body") {
          return `${prefix} ${selector}`;
        }
        return prefixedSelector;
      },
      includeFiles: [/bootstrap-prefixed\.css$/],
    },
  },
},
```
3. Tailwind 保持全局自由发挥,不影响 Bootstrap。`html` 和 `body` 特殊处理,避免基础样式被限制。
  • 效果:两套 CSS 各玩各的,不踩地盘。Tailwind 是"自由派设计师",Bootstrap 是"规矩老板",加个前缀就能让他们和平共处,同时还可以保证布局一致性。

🤔 Reflect

🌟 这是我第一次用 Nuxt3 打造公司官网,整个过程充满了各种曲折与探索。

从配置环境、封装 API,到处理服务端渲染和部署,每一步都像在解谜,踩过不少坑,也学到了很多新技能。

如果文章里有任何不准确或者可优化的地方,非常欢迎大家指正和交流。

希望我的这次实战经验,能给同样第一次尝试 Nuxt3 的你一些参考和启发。

让我们一起探索,让官网不仅上线,更一步步完善成长吧!

相关推荐
刺客-Andy17 分钟前
React 第七十节 Router中matchRoutes的使用详解及注意事项
前端·javascript·react.js
前端工作日常32 分钟前
我对eslint的进一步学习
前端·eslint
禁止摆烂_才浅1 小时前
VsCode 概览尺、装订线、代码块高亮设置
前端·visual studio code
程序员猫哥2 小时前
vue跳转页面的几种方法(推荐)
前端
代码老y2 小时前
十年回望:Vue 与 React 的设计哲学、演进轨迹与生态博弈
前端·vue.js·react.js
一条上岸小咸鱼2 小时前
Kotlin 基本数据类型(五):Array
android·前端·kotlin
大明882 小时前
用 mouseover/mouseout 事件代理模拟 mouseenter/mouseleave
前端·javascript
小杨梅君2 小时前
vue3+vite中使用自定义element-plus主题配置
前端·element
一个专注api接口开发的小白2 小时前
Python + 淘宝 API 开发:自动化采集商品数据的完整流程
前端·数据挖掘·api
林太白2 小时前
Nuxt.js搭建一个官网如何简单
前端·javascript·后端