全部文章

Vue 3 / Nuxt 开发笔记

Vue 3 Composition API、Nuxt 3 常用模式、自动导入与部署配置

目录 21 节

Vue 3 / Nuxt 开发笔记

这页适合已经会写基础前端、准备把 Vue 3 / Nuxt 3 用顺手的人。阅读时可以把它当成“从组件开发到全栈页面交付”的中间层笔记,而不是单纯 API 速查。

推荐学习顺序

如果你是第一次系统接触 Vue 3 / Nuxt,建议按这个顺序走:

  1. 先理解 refreactivecomputedwatch
  2. 再掌握组件通信、Composable 和页面级状态
  3. 然后理解 useFetch / useAsyncData / 服务端 API 的边界
  4. 最后补 SEO、路由中间件、部署和环境变量

先把“响应式”和“数据流”理顺,后面的 SSR、缓存、SEO 才不容易踩坑。

Vue 3 Composition API

响应式

<script setup lang="ts">
const count = ref(0);
const doubled = computed(() => count.value * 2);

const user = reactive({
  name: "Domi",
  age: 20,
});

// 监听
watch(count, (newVal, oldVal) => {
  console.log(`${oldVal} -> ${newVal}`);
});

// 监听多个
watch([count, () => user.name], ([c, n]) => {
  console.log(c, n);
});

// 立即执行的副作用
watchEffect(() => {
  console.log(`count is ${count.value}`);
});
</script>

生命周期

<script setup lang="ts">
onMounted(() => {
  /* DOM 已挂载 */
});
onUnmounted(() => {
  /* 清理 */
});
onBeforeUpdate(() => {
  /* 更新前 */
});
</script>

组合式函数(Composable)

// composables/useMouse.ts
export function useMouse() {
  const x = ref(0);
  const y = ref(0);

  function update(e: MouseEvent) {
    x.value = e.pageX;
    y.value = e.pageY;
  }

  onMounted(() => window.addEventListener("mousemove", update));
  onUnmounted(() => window.removeEventListener("mousemove", update));

  return { x, y };
}

Props 与 Emits

<script setup lang="ts">
const props = defineProps<{
  title: string;
  count?: number;
}>();

const emit = defineEmits<{
  update: [value: string];
  close: [];
}>();

// 带默认值
const props = withDefaults(
  defineProps<{
    size?: "sm" | "md" | "lg";
  }>(),
  {
    size: "md",
  },
);
</script>

Nuxt 常用模式

数据获取

<script setup lang="ts">
// SSR 友好的数据获取
const { data, pending, error, refresh } = await useFetch("/api/users");

// 带缓存键
const { data } = await useAsyncData("users", () => $fetch("/api/users"));

// 仅客户端
const { data } = await useFetch("/api/data", { lazy: true });
</script>

路由与中间件

// middleware/auth.ts
export default defineNuxtRouteMiddleware((to, from) => {
  const user = useUserStore();
  if (!user.isLoggedIn) {
    return navigateTo("/login");
  }
});

页面中使用:

<script setup lang="ts">
definePageMeta({
  middleware: "auth",
  layout: "admin",
});
</script>

SEO

<script setup lang="ts">
useHead({
  title: "页面标题",
  meta: [{ name: "description", content: "页面描述" }],
});

// 或使用组件
useSeoMeta({
  title: "页面标题",
  ogTitle: "页面标题",
  description: "页面描述",
  ogDescription: "页面描述",
});
</script>

服务端 API

// server/api/hello.get.ts
export default defineEventHandler((event) => {
  return { message: "Hello World" };
});

// server/api/users.post.ts
export default defineEventHandler(async (event) => {
  const body = await readBody(event);
  return { created: true };
});

常见目录约定

Nuxt 的目录约定本身就是开发效率的一部分,推荐至少记住下面这些高频目录:

app/
components/      # 通用组件
composables/     # 复用逻辑
layouts/         # 页面框架
middleware/      # 路由守卫
pages/           # 文件路由
server/api/      # 服务端接口
server/utils/    # 服务端工具函数
content/         # 内容型站点数据

经验上:

  • 组件负责展示,Composable 负责复用逻辑
  • 页面负责拼装数据,不要把所有请求都塞进组件
  • 服务端接口负责保护密钥、聚合第三方请求、做输入校验

数据获取怎么选

几个常见 API 的使用边界可以这样理解:

  • useFetch:页面 / 组件里最常用,支持 SSR,适合直接请求接口
  • useAsyncData:更灵活,适合把请求逻辑封装成函数并复用缓存键
  • $fetch:更像底层请求方法,适合在事件、Composable、服务端逻辑中手动调用

简单判断:

  • 首屏要展示的数据:优先 useFetch / useAsyncData
  • 点击按钮后才请求:优先 $fetch
  • 依赖私密环境变量或第三方密钥:优先在 server/api 里中转

常见坑

Hydration mismatch

服务端和客户端渲染结果不一致时,经常会出现 hydration 警告。高频原因包括:

  • 模板里直接使用 windowdocument
  • 服务端渲染时取不到浏览器 API
  • 使用了带随机值、当前时间、屏幕尺寸的初始渲染内容

遇到这类问题时,可以把仅浏览器执行的逻辑放到 onMounted 中,或者明确使用客户端组件策略。

Composable 里副作用过多

Composable 最容易被写成“隐形全局状态”。建议尽量避免:

  • 在导入时立即发请求
  • 在函数外层创建会跨页面污染的可变状态
  • 把页面级业务规则和通用逻辑硬绑在一起

环境变量边界混乱

Nuxt 项目里,优先把公开配置放进 runtimeConfig.public,私密配置放进 runtimeConfig。不要把服务端密钥直接暴露给前端页面。

部署前检查

  • 路由命名是否清晰,动态参数页是否能正确处理空值
  • 页面首屏数据是否支持 SSR
  • useSeoMeta 是否覆盖标题、描述、开放图基础字段
  • 环境变量是否区分本地、预览、生产
  • 第三方接口是否经过服务端转发与兜底处理

延伸阅读

常用库

说明
VueUseVue 组合式工具集
Pinia状态管理
UnoCSS原子化 CSS
Nuxt Content内容管理
Nuxt Image图片优化

参考链接

阅读建议
  • - 先读标题和摘要,再结合目录决定从哪个章节开始精读。
  • - 看到具体命令、配置或步骤时,尽量在自己的环境里同步验证。
  • - 如果你只是快速查资料,可先看目录和相关文档,再决定是否深入全文。
适合谁看
  • - 希望把零散经验整理成长期可复用工作流的人
  • - 想先建立认知,再决定是否深入实践的人
  • - 希望阅读时顺手建立自己的操作清单或收藏体系的人
执行前检查
  • - 先浏览标题、摘要和目录,带着问题阅读会更高效
  • - 顺手记录真正对你有用的命令、链接和注意事项,避免重复搜索
  • - 如果页面里提到相关文档,尽量一起打开对照,效果通常更完整
同类内容
← 上一篇VPS 初始化配置