[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"public:announcements":3,"public:navigations:zh":4,"footer:categories:zh":56,"post:detail:post-3-Vue3组合式:zh":177},[],[5,18,25,33,41,49],{"id":6,"title":7,"url":12,"icon":13,"parent_id":13,"location":14,"order":6,"is_active":15,"target_blank":16,"created_at":17,"updated_at":13},1,{"zh":8,"en":9,"ja":10,"zh_TW":11},"首页","Home","ホーム","首頁","\u002F",null,"header",true,false,"2026-09-30T18:09:54.251095Z",{"id":19,"title":20,"url":24,"icon":13,"parent_id":13,"location":14,"order":19,"is_active":15,"target_blank":16,"created_at":17,"updated_at":13},2,{"zh":21,"en":22,"ja":23,"zh_TW":21},"文章","Posts","記事","\u002Fposts",{"id":26,"title":27,"url":32,"icon":13,"parent_id":13,"location":14,"order":26,"is_active":15,"target_blank":16,"created_at":17,"updated_at":13},3,{"zh":28,"en":29,"ja":30,"zh_TW":31},"分类","Categories","カテゴリー","分類","\u002Fcategories",{"id":34,"title":35,"url":40,"icon":13,"parent_id":13,"location":14,"order":34,"is_active":15,"target_blank":16,"created_at":17,"updated_at":13},4,{"zh":36,"en":37,"ja":38,"zh_TW":39},"标签","Tags","タグ","標籤","\u002Ftags",{"id":42,"title":43,"url":48,"icon":13,"parent_id":13,"location":14,"order":42,"is_active":15,"target_blank":16,"created_at":17,"updated_at":13},5,{"zh":44,"en":45,"ja":46,"zh_TW":47},"关于","About","概要","關於","\u002Fpage\u002Fabout",{"id":50,"title":51,"url":55,"icon":13,"parent_id":13,"location":14,"order":50,"is_active":15,"target_blank":16,"created_at":17,"updated_at":13},6,{"zh":52,"en":53,"ja":54,"zh_TW":52},"留言板","Guestbook","ゲストブック","\u002Fpage\u002Fguestbook",[57,73,87,102,117,133,148,162],{"id":6,"name":58,"slug":63,"description":64,"icon":69,"color":70,"cover_image":13,"created_at":71,"post_count":72},{"en":59,"ja":60,"zh":61,"zh_Hant":62},"Technology","テクノロジー","技术","技術","technology",{"en":65,"ja":66,"zh":67,"zh_Hant":68},"Cutting-edge technology exploration and in-depth analysis covering programming languages, frameworks, and architecture design","プログラミング言語、フレームワーク、アーキテクチャ設計を含む先端技術の探究","前沿技术探索与深度分析，涵盖编程语言、框架、架构设计等核心领域","前沿技術探索與深度分析，涵蓋編程語言、框架、架構設計等核心領域","heroicons:cog-6-tooth","#6366f1","2026-09-30T18:09:53.633610Z",8,{"id":19,"name":74,"slug":78,"description":79,"icon":84,"color":85,"cover_image":13,"created_at":86,"post_count":50},{"en":75,"ja":76,"zh":77,"zh_Hant":77},"Tutorial","チュートリアル","教程","tutorial",{"en":80,"ja":81,"zh":82,"zh_Hant":83},"Hands-on tutorials from scratch with clear steps and complete code for developers at all levels","ゼロから始める実践的なチュートリアル。明確な手順と完全なコードで、全てのレベルの開発者に最適","从零开始的实战教程，步骤清晰，代码完整，适合各阶段开发者学习","從零開始的實戰教程，步驟清晰，代碼完整，適合各階段開發者學習","heroicons:academic-cap","#10b981","2026-09-30T18:09:53.641581Z",{"id":26,"name":88,"slug":92,"description":93,"icon":98,"color":99,"cover_image":13,"created_at":100,"post_count":101},{"en":89,"ja":90,"zh":91,"zh_Hant":91},"Frontend","フロントエンド","前端","frontend",{"en":94,"ja":95,"zh":96,"zh_Hant":97},"Full coverage of web frontend development including Vue, React, new CSS features, and performance optimization","Vue、React、CSSの新機能やパフォーマンス最適化を含むWebフロントエンド開発の全領域","Web前端开发全栈覆盖，包括Vue、React、CSS新特性及性能优化等话题","Web前端開發全棧覆蓋，包括Vue、React、CSS新特性及性能優化等話題","heroicons:computer-desktop","#ec4899","2026-09-30T18:09:53.644838Z",7,{"id":34,"name":103,"slug":108,"description":109,"icon":114,"color":115,"cover_image":13,"created_at":116,"post_count":26},{"en":104,"ja":105,"zh":106,"zh_Hant":107},"Backend","バックエンド","后端","後端","backend",{"en":110,"ja":111,"zh":112,"zh_Hant":113},"Server-side development best practices including API design, database optimization, and microservices architecture","API設計、データベース最適化、マイクロサービスアーキテクチャを含むサーバーサイド開発の実践","服务端开发实战经验，API设计、数据库优化、微服务架构等深度内容","服務端開發實戰經驗，API設計、數據庫優化、微服務架構等深度內容","heroicons:server-stack","#f59e0b","2026-09-30T18:09:53.647836Z",{"id":42,"name":118,"slug":123,"description":124,"icon":129,"color":130,"cover_image":13,"created_at":131,"post_count":132},{"en":119,"ja":120,"zh":121,"zh_Hant":122},"Fullstack","フルスタック","全栈","全棧","fullstack",{"en":125,"ja":126,"zh":127,"zh_Hant":128},"End-to-end development guides covering the full project lifecycle and technology stack selection","フロントエンドからバックエンドまでの開発プロセス全体をカバーするガイド","从前端到后端的全流程开发指南，覆盖完整项目生命周期与技术选型","從前端到後端的全流程開發指南，覆蓋完整項目生命週期與技術選型","heroicons:swatch","#8b5cf6","2026-09-30T18:09:53.650513Z",0,{"id":50,"name":134,"slug":139,"description":140,"icon":145,"color":146,"cover_image":13,"created_at":147,"post_count":34},{"en":135,"ja":136,"zh":137,"zh_Hant":138},"Essays","エッセイ","随笔","隨筆","essays",{"en":141,"ja":142,"zh":143,"zh_Hant":144},"Technical reflections and development insights recording the programmer's growth journey","プログラマーの成長の軌跡を記録する技術的考察と開発の洞察","技术思考与开发心得分享，记录程序员成长路上的点滴感悟","技術思考與開發心得分享，記錄程序員成長路上的點滴感悟","heroicons:pencil-square","#f43f5e","2026-09-30T18:09:53.653105Z",{"id":101,"name":149,"slug":153,"description":154,"icon":159,"color":160,"cover_image":13,"created_at":161,"post_count":34},{"en":150,"ja":151,"zh":152,"zh_Hant":152},"Tools","ツール","工具","tools",{"en":155,"ja":156,"zh":157,"zh_Hant":158},"Development toolchain and productivity tool recommendations to supercharge your development experience","開発効率を飛躍的に向上させるツールチェーンと生産性ツールの推奨","开发工具链与效率提升利器推荐，让你的开发体验如虎添翼","開發工具鏈與效率提升利器推薦，讓你的開發體驗如虎添翼","heroicons:wrench-screwdriver","#06b6d4","2026-09-30T18:09:53.655605Z",{"id":72,"name":163,"slug":168,"description":169,"icon":174,"color":175,"cover_image":13,"created_at":176,"post_count":132},{"en":164,"ja":165,"zh":166,"zh_Hant":167},"Translation","翻訳","翻译","翻譯","translation",{"en":170,"ja":171,"zh":172,"zh_Hant":173},"Curated translations of high-quality foreign technical articles to keep up with international trends","国際的な技術トレンドを追うための厳選された海外技術記事の翻訳","优质外文技术文章精选翻译，紧跟国际技术前沿动态","優質外文技術文章精選翻譯，緊跟國際技術前沿動態","heroicons:language","#84cc16","2026-09-30T18:09:53.658041Z",{"id":26,"title":178,"subtitle":13,"slug":179,"source":180,"source_url":13,"audio":13,"video":13,"video_url":13,"content":181,"excerpt":182,"cover_image":13,"author":183,"category":186,"tags":187,"status":202,"visibility":203,"password":13,"views":204,"likes_count":132,"is_pinned":16,"allow_comments":15,"comments_count":34,"is_password_protected":16,"meta_title":178,"meta_description":182,"meta_keywords":205,"created_at":206,"published_at":206,"updated_at":207,"reading_time":6},"Vue 3 组合式 API 实战","post-3-Vue3组合式","原创","# Vue 3 组合式 API 实战\n\n自 Vue 3.0 发布以来，组合式 API 已经从\"新特性\"演变为 Vue 的默认开发范式。它解决了 Options API 在大型组件中逻辑分散、难以复用的核心痛点，同时保留了 Vue 一贯的优雅和直观。\n\n## ref 与 reactive：如何选择？\n\n这是新手最常问的问题。本质上，reactive 适合对象型状态，ref 适合原始类型与\"需要整体替换\"的对象。\n\n```typescript\nimport { ref, computed, watch, onMounted, onBeforeUnmount } from 'vue'\n\nexport interface Product {\n  id: number\n  name: string\n  price: number\n  category: string\n  tags: string[]\n  rating: number\n  inStock: boolean\n}\n\nexport interface FilterOptions {\n  keyword: string\n  categories: string[]\n  priceRange: [number, number]\n  minRating: number\n  inStockOnly: boolean\n}\n\nexport function useProductFilter(initialProducts: Product[]) {\n  const products = ref\u003CProduct[]>(initialProducts)\n  const loading = ref(false)\n  const error = ref\u003Cstring | null>(null)\n\n  const filters = reactive\u003CFilterOptions>({\n    keyword: '',\n    categories: [],\n    priceRange: [0, 10000],\n    minRating: 0,\n    inStockOnly: false\n  })\n\n  const filteredProducts = computed(() => {\n    let result = [...products.value]\n\n    if (filters.keyword) {\n      const kw = filters.keyword.toLowerCase()\n      result = result.filter(p => p.name.toLowerCase().includes(kw))\n    }\n\n    if (filters.categories.length > 0) {\n      result = result.filter(p => filters.categories.includes(p.category))\n    }\n\n    result = result.filter(p =>\n      p.price >= filters.priceRange[0] &&\n      p.price \u003C= filters.priceRange[1]\n    )\n\n    if (filters.minRating > 0) {\n      result = result.filter(p => p.rating >= filters.minRating)\n    }\n\n    if (filters.inStockOnly) {\n      result = result.filter(p => p.inStock)\n    }\n\n    return result\n  })\n\n  const stats = computed(() => ({\n    total: filteredProducts.value.length,\n    maxPrice: Math.max(0, ...filteredProducts.value.map(p => p.price)),\n    avgRating: filteredProducts.value.length\n      ? filteredProducts.value.reduce((s, p) => s + p.rating, 0) \u002F filteredProducts.value.length\n      : 0\n  }))\n\n  function resetFilters() {\n    filters.keyword = ''\n    filters.categories = []\n    filters.priceRange = [0, 10000]\n    filters.minRating = 0\n    filters.inStockOnly = false\n  }\n\n  function toggleCategory(cat: string) {\n    const i = filters.categories.indexOf(cat)\n    i >= 0 ? filters.categories.splice(i, 1) : filters.categories.push(cat)\n  }\n\n  let unwatch: (() => void) | null = null\n  onMounted(() => {\n    unwatch = watch(\n      () => [filters.keyword, filters.priceRange[1]],\n      async () => {\n        \u002F\u002F 模拟统计上报\n        console.log('[analytics] filter changed')\n      },\n      { deep: false, flush: 'post' }\n    )\n  })\n\n  onBeforeUnmount(() => {\n    unwatch?.()\n  })\n\n  return {\n    products,\n    loading,\n    error,\n    filters,\n    filteredProducts,\n    stats,\n    resetFilters,\n    toggleCategory\n  }\n}\n```\n\n## 两种响应式声明对比\n\n| 维度 | ref | reactive |\n|:---|:---|:---|\n| 支持原始类型 | ✅ string\u002Fnumber\u002Fboolean 等 | ❌ 仅支持对象\u002F数组 |\n| 访问方式 | `.value` 读写 | 直接读写属性 |\n| 解构赋值 | ✅ 保持响应性 | ❌ 丢失响应性（需 toRefs） |\n| 整体替换 | `obj.value = newObj` 安全 | `Object.assign` 手动合并 |\n| TS 类型推断 | 直观 `Ref\u003CT>` | 递归 unwrap 易混淆 |\n| 内存开销 | 稍高（包装对象） | 略低（Proxy 直接包裹） |\n\n## Composable 抽取的三条黄金原则\n\n代码示例中的 `useProductFilter` 就是一个典型的 Composable。好的 Composable 应该遵循：\n\n1. **单一职责**：每个 Composable 只做一件事。不要写出 `useProductFilterWithAuthAndAnalytics` 这样的怪物\n2. **显式返回值**：使用 `return { a, b, c }` 而非返回 reactive 对象，让调用方知道自己用了什么\n3. **生命周期对称**：在 Composable 内部申请的资源（监听、定时器、事件订阅）一定要在 onBeforeUnmount 中释放\n\n## 避免常见的性能陷阱\n\n组合式 API 虽然灵活，但也容易踩坑：\n\n```ts\n\u002F\u002F ❌ 错误：每次渲染都重新计算巨大数组\nconst sorted = [...products.value].sort(heavySortFn)\n\n\u002F\u002F ✅ 正确：用 computed 缓存结果\nconst sorted = computed(() => [...products.value].sort(heavySortFn))\n\n\u002F\u002F ❌ 错误：watch 开启 deep 监听大型对象\nwatch(hugeObject, handler, { deep: true })\n\n\u002F\u002F ✅ 更好：只监听关心的字段\nwatch(() => hugeObject.items[0].status, handler)\n```\n\n## 最佳实践\n\n1. **用 `computed` 包装所有派生状态**，不要在 template 里写复杂表达式\n2. **组合式函数命名统一 `useXxx` 前缀**，文件命名也对应 `useXxx.ts`\n3. **Provide\u002FInject 搭配 Composable 使用**，在根级 Provider 组件中统一管理全局状态\n4. **不要把 template 专用的计算逻辑放在 Composable 里**，保持它的普适性\n5. **使用 `unref()` 和 `isRef()`** 编写既能接受 Ref 又能接受普通值的工具函数\n\n## 总结\n\n组合式 API 的核心价值在于\"逻辑关注点聚合\"与\"复用粒度精细\"。把 Options API 时代散落的 data\u002Fmethods\u002Fcomputed\u002Fwatch 按业务领域重新组织成一个个可测试、可组合的单元，才是它真正的威力所在。掌握 Composable 的设计，你的 Vue 代码质量会迎来质的飞跃。","Vue 3 的组合式 API (Composition API) 彻底改变了 Vue 组件的组织方式。本文通过构建一个复杂的电商筛选器组件，演示 ref\u002Freactive 的选择、computed\u002Fwatch 的合理使用、自定义组合函数 (Composable) 的抽离原则、生命周期钩子的时机以及 provide\u002Finject 进行跨层级状态传递的正确姿势。",{"id":6,"username":184,"nickname":184,"avatar":13,"cover_image":13,"bio":13,"website":13,"github":13,"avatar_source":13,"resolved_avatar_url":13,"title":13,"created_at":185},"Choyeon","2026-09-30T18:09:53.330367Z",{"id":26,"name":91,"slug":92,"description":96,"icon":98,"color":99,"cover_image":13,"created_at":100,"post_count":132},[188,193,198],{"id":26,"name":189,"slug":190,"color":191,"icon":13,"is_active":15,"created_at":192,"post_count":132},"Vue","vue","#42b883","2026-09-30T18:09:53.672512Z",{"id":50,"name":194,"slug":195,"color":196,"icon":13,"is_active":15,"created_at":197,"post_count":132},"TypeScript","typescript","#3178c6","2026-09-30T18:09:53.680697Z",{"id":199,"name":89,"slug":92,"color":200,"icon":13,"is_active":15,"created_at":201,"post_count":132},26,"#94a3b8","2026-09-30T18:09:53.760103Z","published","public",620,"Vue,TypeScript,Frontend","2026-08-21T15:09:53.733462Z","2026-09-30T21:02:54.379568Z"]