[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"knowledge-\u002Fapi\u002Fknowledge\u002Fbooklet\u002Fframe\u002Fvue\u002Fprops":3,"knowledge-related-\u002Fknowledge\u002Fbooklet\u002Fframe\u002Fvue\u002Fprops":2173,"knowledge-series-\u002Fknowledge\u002Fbooklet\u002Fframe\u002Fvue\u002Fprops":2198},{"source":4,"connector":5,"page":6},"sqlite","better-sqlite3",{"path":7,"title":8,"description":9,"category":10,"tags":11,"date":14,"pinned":15,"draft":15,"body":16,"seo":2169,"stem":2170,"id":2171,"extension":2172},"\u002Fknowledge\u002Fbooklet\u002Fframe\u002Fvue\u002Fprops","组件通信与跨层级设计模式","Vue 提供 props \u002F emit、v-model、provide\u002Finject、插槽等多种通信方式。见 Vue 基础。","技能小册",[12,13],"vue","props","2023-03-23",false,{"type":17,"value":18,"toc":2157},"minimark",[19,22,32,35,40,50,57,218,225,229,236,400,407,411,421,425,435,578,586,592,619,626,630,633,766,769,773,783,787,806,812,819,832,835,915,932,1025,1033,1038,1264,1268,1287,1348,1359,1406,1410,1413,1417,1431,1611,1614,1618,1621,1674,1684,1688,1695,1699,1710,1716,1776,1783,1792,1899,1912,1916,1945,1949,2067,2085,2089,2092,2153],[20,21,8],"h1",{"id":8},[23,24,25,26,31],"p",{},"Vue 提供 props \u002F emit、v-model、provide\u002Finject、插槽等多种通信方式。见 ",[27,28,30],"a",{"href":29},"\u002Fknowledge\u002Fbooklet\u002Fframe\u002Fvue\u002Fbasics","Vue 基础","。",[23,33,34],{},"Vue 提供了多种组件间通信方式，适用于不同场景：从父子组件直接的 props\u002Femit，到跨越多层级的 provide\u002Finject，再到灵活的插槽和实例引用。合理选择通信模式可以保持组件的可维护性和可测试性。",[36,37,39],"h3",{"id":38},"一props-的高级模式","一、Props 的高级模式",[41,42,44,45,49],"h4",{"id":43},"_1-v-bindobject-批量传递-props","1. ",[46,47,48],"code",{},"v-bind=\"object\""," 批量传递 props",[23,51,52,53,56],{},"当一个对象包含多个属性需要作为 props 传递给子组件时，可以使用 ",[46,54,55],{},"v-bind"," 不带参数的形式批量绑定。",[58,59,63],"pre",{"className":60,"code":61,"language":12,"meta":62,"style":62},"language-vue shiki shiki-themes material-theme-lighter github-light github-dark","\u003Ctemplate>\n  \u003CUserProfile v-bind=\"userInfo\" \u002F>\n\u003C\u002Ftemplate>\n\n\u003Cscript setup>\nconst userInfo = { name: \"Alice\", age: 25, email: \"alice@example.com\" };\n\u002F\u002F 等价于 \u003CUserProfile :name=\"userInfo.name\" :age=\"userInfo.age\" :email=\"userInfo.email\" \u002F>\n\u003C\u002Fscript>\n","",[46,64,65,81,110,120,127,140,202,209],{"__ignoreMap":62},[66,67,70,74,78],"span",{"class":68,"line":69},"line",1,[66,71,73],{"class":72},"sP7_E","\u003C",[66,75,77],{"class":76},"sQzsp","template",[66,79,80],{"class":72},">\n",[66,82,84,87,90,94,97,101,105,107],{"class":68,"line":83},2,[66,85,86],{"class":72},"  \u003C",[66,88,89],{"class":76},"UserProfile",[66,91,93],{"class":92},"s9AJx"," v-bind",[66,95,96],{"class":72},"=",[66,98,100],{"class":99},"sjJ54","\"",[66,102,104],{"class":103},"s_sjI","userInfo",[66,106,100],{"class":99},[66,108,109],{"class":72}," \u002F>\n",[66,111,113,116,118],{"class":68,"line":112},3,[66,114,115],{"class":72},"\u003C\u002F",[66,117,77],{"class":76},[66,119,80],{"class":72},[66,121,123],{"class":68,"line":122},4,[66,124,126],{"emptyLinePlaceholder":125},true,"\n",[66,128,130,132,135,138],{"class":68,"line":129},5,[66,131,73],{"class":72},[66,133,134],{"class":76},"script",[66,136,137],{"class":92}," setup",[66,139,80],{"class":72},[66,141,143,147,151,155,158,162,165,168,171,173,176,179,181,185,187,190,192,194,197,199],{"class":68,"line":142},6,[66,144,146],{"class":145},"sbsja","const",[66,148,150],{"class":149},"s_hVV"," userInfo",[66,152,154],{"class":153},"smGrS"," =",[66,156,157],{"class":72}," {",[66,159,161],{"class":160},"skxfh"," name",[66,163,164],{"class":72},":",[66,166,167],{"class":99}," \"",[66,169,170],{"class":103},"Alice",[66,172,100],{"class":99},[66,174,175],{"class":72},",",[66,177,178],{"class":160}," age",[66,180,164],{"class":72},[66,182,184],{"class":183},"srdBf"," 25",[66,186,175],{"class":72},[66,188,189],{"class":160}," email",[66,191,164],{"class":72},[66,193,167],{"class":99},[66,195,196],{"class":103},"alice@example.com",[66,198,100],{"class":99},[66,200,201],{"class":72}," };\n",[66,203,205],{"class":68,"line":204},7,[66,206,208],{"class":207},"sutJx","\u002F\u002F 等价于 \u003CUserProfile :name=\"userInfo.name\" :age=\"userInfo.age\" :email=\"userInfo.email\" \u002F>\n",[66,210,212,214,216],{"class":68,"line":211},8,[66,213,115],{"class":72},[66,215,134],{"class":76},[66,217,80],{"class":72},[23,219,220,221,224],{},"这在封装高阶组件或转发 props 时非常有用，可以结合 ",[46,222,223],{},"$attrs"," 实现透传。",[41,226,228],{"id":227},"_2-单向数据流下的修改提议emit-事件","2. 单向数据流下的修改提议（emit 事件）",[23,230,231,232,235],{},"Vue 强制单向数据流：父组件通过 props 传递数据，子组件不能直接修改 props。若子组件需要“提议”修改，应通过 ",[46,233,234],{},"emit"," 触发事件，由父组件实际执行修改。",[58,237,239],{"className":60,"code":238,"language":12,"meta":62,"style":62},"\u003C!-- 子组件 -->\n\u003Cscript setup>\nconst props = defineProps([\"modelValue\"]);\nconst emit = defineEmits([\"update:modelValue\"]);\nfunction updateValue(newVal) {\n  emit(\"update:modelValue\", newVal);\n}\n\u003C\u002Fscript>\n\n\u003C!-- 父组件 -->\n\u003CChildComponent v-model=\"parentData\" \u002F>\n",[46,240,241,246,256,286,311,332,354,359,367,372,378],{"__ignoreMap":62},[66,242,243],{"class":68,"line":69},[66,244,245],{"class":207},"\u003C!-- 子组件 -->\n",[66,247,248,250,252,254],{"class":68,"line":83},[66,249,73],{"class":72},[66,251,134],{"class":76},[66,253,137],{"class":92},[66,255,80],{"class":72},[66,257,258,260,263,265,269,273,275,278,280,283],{"class":68,"line":112},[66,259,146],{"class":145},[66,261,262],{"class":149}," props",[66,264,154],{"class":153},[66,266,268],{"class":267},"sGLFI"," defineProps",[66,270,272],{"class":271},"su5hD","([",[66,274,100],{"class":99},[66,276,277],{"class":103},"modelValue",[66,279,100],{"class":99},[66,281,282],{"class":271},"])",[66,284,285],{"class":72},";\n",[66,287,288,290,293,295,298,300,302,305,307,309],{"class":68,"line":122},[66,289,146],{"class":145},[66,291,292],{"class":149}," emit",[66,294,154],{"class":153},[66,296,297],{"class":267}," defineEmits",[66,299,272],{"class":271},[66,301,100],{"class":99},[66,303,304],{"class":103},"update:modelValue",[66,306,100],{"class":99},[66,308,282],{"class":271},[66,310,285],{"class":72},[66,312,313,316,319,322,326,329],{"class":68,"line":129},[66,314,315],{"class":145},"function",[66,317,318],{"class":267}," updateValue",[66,320,321],{"class":72},"(",[66,323,325],{"class":324},"s99_P","newVal",[66,327,328],{"class":72},")",[66,330,331],{"class":72}," {\n",[66,333,334,337,339,341,343,345,347,350,352],{"class":68,"line":142},[66,335,336],{"class":267},"  emit",[66,338,321],{"class":160},[66,340,100],{"class":99},[66,342,304],{"class":103},[66,344,100],{"class":99},[66,346,175],{"class":72},[66,348,349],{"class":271}," newVal",[66,351,328],{"class":160},[66,353,285],{"class":72},[66,355,356],{"class":68,"line":204},[66,357,358],{"class":72},"}\n",[66,360,361,363,365],{"class":68,"line":211},[66,362,115],{"class":72},[66,364,134],{"class":76},[66,366,80],{"class":72},[66,368,370],{"class":68,"line":369},9,[66,371,126],{"emptyLinePlaceholder":125},[66,373,375],{"class":68,"line":374},10,[66,376,377],{"class":207},"\u003C!-- 父组件 -->\n",[66,379,381,383,386,389,391,393,396,398],{"class":68,"line":380},11,[66,382,73],{"class":72},[66,384,385],{"class":76},"ChildComponent",[66,387,388],{"class":92}," v-model",[66,390,96],{"class":72},[66,392,100],{"class":99},[66,394,395],{"class":271},"parentData",[66,397,100],{"class":99},[66,399,109],{"class":72},[23,401,402,403,406],{},"对于复杂对象的局部修改，推荐在子组件中复制一份到本地 ",[46,404,405],{},"ref"," 或者发出完整的新对象，避免直接 mutation。",[36,408,410],{"id":409},"二provide-inject-的深层机制","二、provide \u002F inject 的深层机制",[23,412,413,416,417,420],{},[46,414,415],{},"provide"," 和 ",[46,418,419],{},"inject"," 用于解决深层嵌套组件之间的通信，避免了逐层传递 props 的麻烦。",[41,422,424],{"id":423},"_1-响应式数据的跨层级注入","1. 响应式数据的跨层级注入",[23,426,427,428,430,431,434],{},"为了实现后代组件能够响应式地更新祖先提供的数据，应当注入 ",[46,429,405],{}," 或 ",[46,432,433],{},"reactive"," 对象。",[58,436,440],{"className":437,"code":438,"language":439,"meta":62,"style":62},"language-js shiki shiki-themes material-theme-lighter github-light github-dark","\u002F\u002F 祖先组件\nimport { ref, provide } from \"vue\";\nconst theme = ref(\"dark\");\nprovide(\"theme\", theme);\n\n\u002F\u002F 后代组件\nimport { inject } from \"vue\";\nconst theme = inject(\"theme\");\n\u002F\u002F 现在 theme 是一个 ref，修改 theme.value 会同步到祖先，并触发相应更新\n","js",[46,441,442,447,477,501,521,525,530,551,573],{"__ignoreMap":62},[66,443,444],{"class":68,"line":69},[66,445,446],{"class":207},"\u002F\u002F 祖先组件\n",[66,448,449,453,455,458,460,463,466,469,471,473,475],{"class":68,"line":83},[66,450,452],{"class":451},"sVHd0","import",[66,454,157],{"class":72},[66,456,457],{"class":271}," ref",[66,459,175],{"class":72},[66,461,462],{"class":271}," provide",[66,464,465],{"class":72}," }",[66,467,468],{"class":451}," from",[66,470,167],{"class":99},[66,472,12],{"class":103},[66,474,100],{"class":99},[66,476,285],{"class":72},[66,478,479,481,484,486,488,490,492,495,497,499],{"class":68,"line":112},[66,480,146],{"class":145},[66,482,483],{"class":149}," theme",[66,485,154],{"class":153},[66,487,457],{"class":267},[66,489,321],{"class":271},[66,491,100],{"class":99},[66,493,494],{"class":103},"dark",[66,496,100],{"class":99},[66,498,328],{"class":271},[66,500,285],{"class":72},[66,502,503,505,507,509,512,514,516,519],{"class":68,"line":122},[66,504,415],{"class":267},[66,506,321],{"class":271},[66,508,100],{"class":99},[66,510,511],{"class":103},"theme",[66,513,100],{"class":99},[66,515,175],{"class":72},[66,517,518],{"class":271}," theme)",[66,520,285],{"class":72},[66,522,523],{"class":68,"line":129},[66,524,126],{"emptyLinePlaceholder":125},[66,526,527],{"class":68,"line":142},[66,528,529],{"class":207},"\u002F\u002F 后代组件\n",[66,531,532,534,536,539,541,543,545,547,549],{"class":68,"line":204},[66,533,452],{"class":451},[66,535,157],{"class":72},[66,537,538],{"class":271}," inject",[66,540,465],{"class":72},[66,542,468],{"class":451},[66,544,167],{"class":99},[66,546,12],{"class":103},[66,548,100],{"class":99},[66,550,285],{"class":72},[66,552,553,555,557,559,561,563,565,567,569,571],{"class":68,"line":211},[66,554,146],{"class":145},[66,556,483],{"class":149},[66,558,154],{"class":153},[66,560,538],{"class":267},[66,562,321],{"class":271},[66,564,100],{"class":99},[66,566,511],{"class":103},[66,568,100],{"class":99},[66,570,328],{"class":271},[66,572,285],{"class":72},[66,574,575],{"class":68,"line":369},[66,576,577],{"class":207},"\u002F\u002F 现在 theme 是一个 ref，修改 theme.value 会同步到祖先，并触发相应更新\n",[41,579,581,582,585],{"id":580},"_2-为-provide-的值添加-readonly-以控制修改权限","2. 为 provide 的值添加 ",[46,583,584],{},"readonly"," 以控制修改权限",[23,587,588,589,591],{},"有时希望后代组件可以读取值但不能修改，可以使用 ",[46,590,584],{}," 包装。",[58,593,595],{"className":437,"code":594,"language":439,"meta":62,"style":62},"provide(\"theme\", readonly(theme));\n",[46,596,597],{"__ignoreMap":62},[66,598,599,601,603,605,607,609,611,614,617],{"class":68,"line":69},[66,600,415],{"class":267},[66,602,321],{"class":271},[66,604,100],{"class":99},[66,606,511],{"class":103},[66,608,100],{"class":99},[66,610,175],{"class":72},[66,612,613],{"class":267}," readonly",[66,615,616],{"class":271},"(theme))",[66,618,285],{"class":72},[23,620,621,622,625],{},"这样后代组件若尝试修改 ",[46,623,624],{},"theme.value"," 会在开发模式下产生警告。",[41,627,629],{"id":628},"_3-在-provide-中注入函数供后代调用","3. 在 provide 中注入函数供后代调用",[23,631,632],{},"除了注入状态，也可以注入方法，让后代组件能够调用祖先组件中定义的逻辑（如更新数据、发起请求等）。",[58,634,636],{"className":437,"code":635,"language":439,"meta":62,"style":62},"\u002F\u002F 祖先\nconst updateUser = (newUser) => {\n  user.value = newUser;\n};\nprovide(\"updateUser\", updateUser);\n\n\u002F\u002F 后代\nconst updateUser = inject(\"updateUser\");\nupdateUser({ name: \"Bob\" });\n",[46,637,638,643,666,684,689,709,713,718,740],{"__ignoreMap":62},[66,639,640],{"class":68,"line":69},[66,641,642],{"class":207},"\u002F\u002F 祖先\n",[66,644,645,647,651,653,656,659,661,664],{"class":68,"line":83},[66,646,146],{"class":145},[66,648,650],{"class":649},"sfCm-"," updateUser",[66,652,154],{"class":153},[66,654,655],{"class":72}," (",[66,657,658],{"class":324},"newUser",[66,660,328],{"class":72},[66,662,663],{"class":145}," =>",[66,665,331],{"class":72},[66,667,668,671,674,677,679,682],{"class":68,"line":112},[66,669,670],{"class":271},"  user",[66,672,673],{"class":72},".",[66,675,676],{"class":271},"value",[66,678,154],{"class":153},[66,680,681],{"class":271}," newUser",[66,683,285],{"class":72},[66,685,686],{"class":68,"line":122},[66,687,688],{"class":72},"};\n",[66,690,691,693,695,697,700,702,704,707],{"class":68,"line":129},[66,692,415],{"class":267},[66,694,321],{"class":271},[66,696,100],{"class":99},[66,698,699],{"class":103},"updateUser",[66,701,100],{"class":99},[66,703,175],{"class":72},[66,705,706],{"class":271}," updateUser)",[66,708,285],{"class":72},[66,710,711],{"class":68,"line":142},[66,712,126],{"emptyLinePlaceholder":125},[66,714,715],{"class":68,"line":204},[66,716,717],{"class":207},"\u002F\u002F 后代\n",[66,719,720,722,724,726,728,730,732,734,736,738],{"class":68,"line":211},[66,721,146],{"class":145},[66,723,650],{"class":149},[66,725,154],{"class":153},[66,727,538],{"class":267},[66,729,321],{"class":271},[66,731,100],{"class":99},[66,733,699],{"class":103},[66,735,100],{"class":99},[66,737,328],{"class":271},[66,739,285],{"class":72},[66,741,742,744,746,749,751,753,755,758,760,762,764],{"class":68,"line":369},[66,743,699],{"class":267},[66,745,321],{"class":271},[66,747,748],{"class":72},"{",[66,750,161],{"class":160},[66,752,164],{"class":72},[66,754,167],{"class":99},[66,756,757],{"class":103},"Bob",[66,759,100],{"class":99},[66,761,465],{"class":72},[66,763,328],{"class":271},[66,765,285],{"class":72},[23,767,768],{},"这种方式实现了“控制反转”，后代组件不需要知道具体实现细节，符合依赖倒置原则。",[41,770,772],{"id":771},"_4-适用场景","4. 适用场景",[774,775,776,780],"ul",{},[777,778,779],"li",{},"主题切换（theme）、语言国际化（locale）、用户认证信息（user）等跨越多层但非全局的状态。",[777,781,782],{},"组件库内部通信（如 Form 和 FormItem 之间）。",[41,784,786],{"id":785},"_5-依赖注入-vs-全局状态管理piniavuex","5. 依赖注入 vs 全局状态管理（Pinia\u002FVuex）",[774,788,789,800],{},[777,790,791,795,796,799],{},[792,793,794],"strong",{},"provide\u002Finject","：作用域为",[792,797,798],{},"组件树局部","，提供者和消费者之间存在明确的层级关系，适合在一个子系统内共享状态。它不会在应用全局单例，同一个页面可以有多个独立的 provide 子树。",[777,801,802,805],{},[792,803,804],{},"Pinia\u002FVuex","：全局单例，适合在整个应用中共享状态，并提供 devtools 支持、时间旅行调试等高级功能。",[807,808,809],"blockquote",{},[23,810,811],{},"经验法则：如果状态只在某个子树中需要，使用 provide\u002Finject；如果状态需要跨不同子树甚至应用全局，使用 Pinia。",[36,813,815,816,818],{"id":814},"三attrs-与透传","三、",[46,817,223],{}," 与透传",[23,820,821,823,824,827,828,831],{},[46,822,223],{}," 包含了父组件传递给子组件但",[792,825,826],{},"没有被该子组件声明为 props"," 的属性（包括 class、style 和普通属性）以及事件监听器（",[46,829,830],{},"v-on","）。在封装高阶组件或基础组件时，常需要将这些属性和事件继续向下传递。",[41,833,834],{"id":834},"透传属性和事件",[58,836,838],{"className":60,"code":837,"language":12,"meta":62,"style":62},"\u003C!-- 基础组件 BaseButton -->\n\u003Ctemplate>\n  \u003Cbutton :class=\"$attrs.class\" v-bind=\"$attrs\">\n    \u003Cslot \u002F>\n  \u003C\u002Fbutton>\n\u003C\u002Ftemplate>\n",[46,839,840,845,853,884,898,907],{"__ignoreMap":62},[66,841,842],{"class":68,"line":69},[66,843,844],{"class":207},"\u003C!-- 基础组件 BaseButton -->\n",[66,846,847,849,851],{"class":68,"line":83},[66,848,73],{"class":72},[66,850,77],{"class":76},[66,852,80],{"class":72},[66,854,855,857,860,863,865,867,870,872,874,876,878,880,882],{"class":68,"line":112},[66,856,86],{"class":72},[66,858,859],{"class":76},"button",[66,861,862],{"class":92}," :class",[66,864,96],{"class":72},[66,866,100],{"class":99},[66,868,869],{"class":103},"$attrs.class",[66,871,100],{"class":99},[66,873,93],{"class":92},[66,875,96],{"class":72},[66,877,100],{"class":99},[66,879,223],{"class":103},[66,881,100],{"class":99},[66,883,80],{"class":72},[66,885,886,889,892,896],{"class":68,"line":122},[66,887,888],{"class":72},"    \u003C",[66,890,891],{"class":76},"slot",[66,893,895],{"class":894},"svtyB"," \u002F",[66,897,80],{"class":72},[66,899,900,903,905],{"class":68,"line":129},[66,901,902],{"class":72},"  \u003C\u002F",[66,904,859],{"class":76},[66,906,80],{"class":72},[66,908,909,911,913],{"class":68,"line":142},[66,910,115],{"class":72},[66,912,77],{"class":76},[66,914,80],{"class":72},[23,916,917,918,921,922,924,925,927,928,931],{},"在组合式 API 中，可以通过 ",[46,919,920],{},"useAttrs()"," 获取 ",[46,923,223],{}," 对象。注意 ",[46,926,223],{}," 不包括已声明的 props，且默认会透传到根元素（如果根元素只有一个）。可以通过设置 ",[46,929,930],{},"inheritAttrs: false"," 关闭自动透传，然后手动控制。",[58,933,935],{"className":60,"code":934,"language":12,"meta":62,"style":62},"\u003Cscript setup>\nconst attrs = useAttrs();\n\u003C\u002Fscript>\n\u003Ctemplate>\n  \u003Cdiv>\n    \u003Cinput v-bind=\"attrs\" \u002F>\n  \u003C\u002Fdiv>\n\u003C\u002Ftemplate>\n",[46,936,937,947,964,972,980,989,1009,1017],{"__ignoreMap":62},[66,938,939,941,943,945],{"class":68,"line":69},[66,940,73],{"class":72},[66,942,134],{"class":76},[66,944,137],{"class":92},[66,946,80],{"class":72},[66,948,949,951,954,956,959,962],{"class":68,"line":83},[66,950,146],{"class":145},[66,952,953],{"class":149}," attrs",[66,955,154],{"class":153},[66,957,958],{"class":267}," useAttrs",[66,960,961],{"class":271},"()",[66,963,285],{"class":72},[66,965,966,968,970],{"class":68,"line":112},[66,967,115],{"class":72},[66,969,134],{"class":76},[66,971,80],{"class":72},[66,973,974,976,978],{"class":68,"line":122},[66,975,73],{"class":72},[66,977,77],{"class":76},[66,979,80],{"class":72},[66,981,982,984,987],{"class":68,"line":129},[66,983,86],{"class":72},[66,985,986],{"class":76},"div",[66,988,80],{"class":72},[66,990,991,993,996,998,1000,1002,1005,1007],{"class":68,"line":142},[66,992,888],{"class":72},[66,994,995],{"class":76},"input",[66,997,93],{"class":92},[66,999,96],{"class":72},[66,1001,100],{"class":99},[66,1003,1004],{"class":103},"attrs",[66,1006,100],{"class":99},[66,1008,109],{"class":72},[66,1010,1011,1013,1015],{"class":68,"line":204},[66,1012,902],{"class":72},[66,1014,986],{"class":76},[66,1016,80],{"class":72},[66,1018,1019,1021,1023],{"class":68,"line":211},[66,1020,115],{"class":72},[66,1022,77],{"class":76},[66,1024,80],{"class":72},[36,1026,1028,1029,1032],{"id":1027},"四refs-与组件实例引用","四、",[46,1030,1031],{},"$refs"," 与组件实例引用",[23,1034,1035,1037],{},[46,1036,1031],{}," 用于直接访问子组件或 DOM 元素。在组合式 API 中，通过声明同名的模板 ref 变量来获取。",[58,1039,1041],{"className":60,"code":1040,"language":12,"meta":62,"style":62},"\u003Ctemplate>\n  \u003CChildComponent ref=\"childRef\" \u002F>\n  \u003Cinput ref=\"inputRef\" \u002F>\n\u003C\u002Ftemplate>\n\n\u003Cscript setup>\nimport { ref, onMounted } from \"vue\";\nconst childRef = ref(null); \u002F\u002F 类型：ComponentPublicInstance 或 null\nconst inputRef = ref(null); \u002F\u002F 类型：HTMLInputElement 或 null\n\nonMounted(() => {\n  console.log(childRef.value); \u002F\u002F 子组件实例\n  inputRef.value.focus();\n});\n\u003C\u002Fscript>\n",[46,1042,1043,1051,1070,1089,1097,1101,1111,1136,1161,1183,1187,1200,1226,1245,1255],{"__ignoreMap":62},[66,1044,1045,1047,1049],{"class":68,"line":69},[66,1046,73],{"class":72},[66,1048,77],{"class":76},[66,1050,80],{"class":72},[66,1052,1053,1055,1057,1059,1061,1063,1066,1068],{"class":68,"line":83},[66,1054,86],{"class":72},[66,1056,385],{"class":76},[66,1058,457],{"class":92},[66,1060,96],{"class":72},[66,1062,100],{"class":99},[66,1064,1065],{"class":103},"childRef",[66,1067,100],{"class":99},[66,1069,109],{"class":72},[66,1071,1072,1074,1076,1078,1080,1082,1085,1087],{"class":68,"line":112},[66,1073,86],{"class":72},[66,1075,995],{"class":76},[66,1077,457],{"class":92},[66,1079,96],{"class":72},[66,1081,100],{"class":99},[66,1083,1084],{"class":103},"inputRef",[66,1086,100],{"class":99},[66,1088,109],{"class":72},[66,1090,1091,1093,1095],{"class":68,"line":122},[66,1092,115],{"class":72},[66,1094,77],{"class":76},[66,1096,80],{"class":72},[66,1098,1099],{"class":68,"line":129},[66,1100,126],{"emptyLinePlaceholder":125},[66,1102,1103,1105,1107,1109],{"class":68,"line":142},[66,1104,73],{"class":72},[66,1106,134],{"class":76},[66,1108,137],{"class":92},[66,1110,80],{"class":72},[66,1112,1113,1115,1117,1119,1121,1124,1126,1128,1130,1132,1134],{"class":68,"line":204},[66,1114,452],{"class":451},[66,1116,157],{"class":72},[66,1118,457],{"class":271},[66,1120,175],{"class":72},[66,1122,1123],{"class":271}," onMounted",[66,1125,465],{"class":72},[66,1127,468],{"class":451},[66,1129,167],{"class":99},[66,1131,12],{"class":103},[66,1133,100],{"class":99},[66,1135,285],{"class":72},[66,1137,1138,1140,1143,1145,1147,1149,1153,1155,1158],{"class":68,"line":211},[66,1139,146],{"class":145},[66,1141,1142],{"class":149}," childRef",[66,1144,154],{"class":153},[66,1146,457],{"class":267},[66,1148,321],{"class":271},[66,1150,1152],{"class":1151},"s39Yj","null",[66,1154,328],{"class":271},[66,1156,1157],{"class":72},";",[66,1159,1160],{"class":207}," \u002F\u002F 类型：ComponentPublicInstance 或 null\n",[66,1162,1163,1165,1168,1170,1172,1174,1176,1178,1180],{"class":68,"line":369},[66,1164,146],{"class":145},[66,1166,1167],{"class":149}," inputRef",[66,1169,154],{"class":153},[66,1171,457],{"class":267},[66,1173,321],{"class":271},[66,1175,1152],{"class":1151},[66,1177,328],{"class":271},[66,1179,1157],{"class":72},[66,1181,1182],{"class":207}," \u002F\u002F 类型：HTMLInputElement 或 null\n",[66,1184,1185],{"class":68,"line":374},[66,1186,126],{"emptyLinePlaceholder":125},[66,1188,1189,1192,1194,1196,1198],{"class":68,"line":380},[66,1190,1191],{"class":267},"onMounted",[66,1193,321],{"class":271},[66,1195,961],{"class":72},[66,1197,663],{"class":145},[66,1199,331],{"class":72},[66,1201,1203,1206,1208,1211,1213,1215,1217,1219,1221,1223],{"class":68,"line":1202},12,[66,1204,1205],{"class":271},"  console",[66,1207,673],{"class":72},[66,1209,1210],{"class":267},"log",[66,1212,321],{"class":160},[66,1214,1065],{"class":271},[66,1216,673],{"class":72},[66,1218,676],{"class":271},[66,1220,328],{"class":160},[66,1222,1157],{"class":72},[66,1224,1225],{"class":207}," \u002F\u002F 子组件实例\n",[66,1227,1229,1232,1234,1236,1238,1241,1243],{"class":68,"line":1228},13,[66,1230,1231],{"class":271},"  inputRef",[66,1233,673],{"class":72},[66,1235,676],{"class":271},[66,1237,673],{"class":72},[66,1239,1240],{"class":267},"focus",[66,1242,961],{"class":160},[66,1244,285],{"class":72},[66,1246,1248,1251,1253],{"class":68,"line":1247},14,[66,1249,1250],{"class":72},"}",[66,1252,328],{"class":271},[66,1254,285],{"class":72},[66,1256,1258,1260,1262],{"class":68,"line":1257},15,[66,1259,115],{"class":72},[66,1261,134],{"class":76},[66,1263,80],{"class":72},[41,1265,1267],{"id":1266},"typescript-类型定义","TypeScript 类型定义",[774,1269,1270,1280],{},[777,1271,1272,1273,1276,1277,31],{},"对于 DOM 元素：使用具体的 ",[46,1274,1275],{},"HTMLElement"," 类型，例如 ",[46,1278,1279],{},"HTMLInputElement",[777,1281,1282,1283,1286],{},"对于组件实例：可以使用 ",[46,1284,1285],{},"InstanceType\u003Ctypeof Component>"," 获取组件实例类型。",[58,1288,1292],{"className":1289,"code":1290,"language":1291,"meta":62,"style":62},"language-ts shiki shiki-themes material-theme-lighter github-light github-dark","import Child from \".\u002FChild.vue\";\nconst childRef = ref\u003CInstanceType\u003Ctypeof Child>>(null);\n","ts",[46,1293,1294,1313],{"__ignoreMap":62},[66,1295,1296,1298,1301,1304,1306,1309,1311],{"class":68,"line":69},[66,1297,452],{"class":451},[66,1299,1300],{"class":271}," Child ",[66,1302,1303],{"class":451},"from",[66,1305,167],{"class":99},[66,1307,1308],{"class":103},".\u002FChild.vue",[66,1310,100],{"class":99},[66,1312,285],{"class":72},[66,1314,1315,1317,1319,1321,1323,1325,1329,1331,1334,1337,1340,1342,1344,1346],{"class":68,"line":83},[66,1316,146],{"class":145},[66,1318,1142],{"class":149},[66,1320,154],{"class":153},[66,1322,457],{"class":267},[66,1324,73],{"class":72},[66,1326,1328],{"class":1327},"sbgvK","InstanceType",[66,1330,73],{"class":72},[66,1332,1333],{"class":153},"typeof",[66,1335,1336],{"class":271}," Child",[66,1338,1339],{"class":72},">>",[66,1341,321],{"class":271},[66,1343,1152],{"class":1151},[66,1345,328],{"class":271},[66,1347,285],{"class":72},[23,1349,1350,1351,1354,1355,1358],{},"注意：子组件需要暴露属性或方法才能在父组件中访问，默认 ",[46,1352,1353],{},"setup"," 下的内容是私有的，需使用 ",[46,1356,1357],{},"defineExpose"," 暴露。",[58,1360,1362],{"className":437,"code":1361,"language":439,"meta":62,"style":62},"\u002F\u002F 子组件\nconst count = ref(0);\ndefineExpose({ count });\n",[46,1363,1364,1369,1389],{"__ignoreMap":62},[66,1365,1366],{"class":68,"line":69},[66,1367,1368],{"class":207},"\u002F\u002F 子组件\n",[66,1370,1371,1373,1376,1378,1380,1382,1385,1387],{"class":68,"line":83},[66,1372,146],{"class":145},[66,1374,1375],{"class":149}," count",[66,1377,154],{"class":153},[66,1379,457],{"class":267},[66,1381,321],{"class":271},[66,1383,1384],{"class":183},"0",[66,1386,328],{"class":271},[66,1388,285],{"class":72},[66,1390,1391,1393,1395,1397,1400,1402,1404],{"class":68,"line":112},[66,1392,1357],{"class":267},[66,1394,321],{"class":271},[66,1396,748],{"class":72},[66,1398,1399],{"class":271}," count ",[66,1401,1250],{"class":72},[66,1403,328],{"class":271},[66,1405,285],{"class":72},[36,1407,1409],{"id":1408},"五插槽的高级模式","五、插槽的高级模式",[23,1411,1412],{},"插槽使得组件的内容可以被父组件定制，作用域插槽进一步允许子组件将内部数据传递给父组件使用。",[41,1414,1416],{"id":1415},"_1-作用域插槽scoped-slots设计可复用组件","1. 作用域插槽（scoped slots）设计可复用组件",[23,1418,1419,1420,1423,1424,430,1427,1430],{},"子组件在 ",[46,1421,1422],{},"\u003Cslot>"," 上绑定 props，父组件通过 ",[46,1425,1426],{},"v-slot",[46,1428,1429],{},"#"," 接收这些数据。",[58,1432,1434],{"className":60,"code":1433,"language":12,"meta":62,"style":62},"\u003C!-- 子组件 DataTable -->\n\u003Ctemplate>\n  \u003Ctable>\n    \u003Ctr v-for=\"item in data\" :key=\"item.id\">\n      \u003Cslot name=\"row\" :row=\"item\" \u002F>\n    \u003C\u002Ftr>\n  \u003C\u002Ftable>\n\u003C\u002Ftemplate>\n\n\u003C!-- 父组件 -->\n\u003CDataTable :data=\"users\">\n  \u003Ctemplate #row=\"{ row }\">\n    \u003Ctd>{{ row.name }}\u003C\u002Ftd>\n    \u003Ctd>{{ row.age }}\u003C\u002Ftd>\n  \u003C\u002Ftemplate>\n\u003C\u002FDataTable>\n",[46,1435,1436,1441,1449,1458,1491,1525,1534,1542,1550,1554,1558,1582,1587,1592,1597,1602],{"__ignoreMap":62},[66,1437,1438],{"class":68,"line":69},[66,1439,1440],{"class":207},"\u003C!-- 子组件 DataTable -->\n",[66,1442,1443,1445,1447],{"class":68,"line":83},[66,1444,73],{"class":72},[66,1446,77],{"class":76},[66,1448,80],{"class":72},[66,1450,1451,1453,1456],{"class":68,"line":112},[66,1452,86],{"class":72},[66,1454,1455],{"class":76},"table",[66,1457,80],{"class":72},[66,1459,1460,1462,1465,1468,1470,1472,1475,1477,1480,1482,1484,1487,1489],{"class":68,"line":122},[66,1461,888],{"class":72},[66,1463,1464],{"class":76},"tr",[66,1466,1467],{"class":92}," v-for",[66,1469,96],{"class":72},[66,1471,100],{"class":99},[66,1473,1474],{"class":103},"item in data",[66,1476,100],{"class":99},[66,1478,1479],{"class":92}," :key",[66,1481,96],{"class":72},[66,1483,100],{"class":99},[66,1485,1486],{"class":103},"item.id",[66,1488,100],{"class":99},[66,1490,80],{"class":72},[66,1492,1493,1496,1498,1500,1502,1504,1507,1509,1512,1514,1516,1519,1521,1523],{"class":68,"line":129},[66,1494,1495],{"class":72},"      \u003C",[66,1497,891],{"class":76},[66,1499,161],{"class":92},[66,1501,96],{"class":72},[66,1503,100],{"class":99},[66,1505,1506],{"class":103},"row",[66,1508,100],{"class":99},[66,1510,1511],{"class":92}," :row",[66,1513,96],{"class":72},[66,1515,100],{"class":99},[66,1517,1518],{"class":103},"item",[66,1520,100],{"class":99},[66,1522,895],{"class":894},[66,1524,80],{"class":72},[66,1526,1527,1530,1532],{"class":68,"line":142},[66,1528,1529],{"class":72},"    \u003C\u002F",[66,1531,1464],{"class":76},[66,1533,80],{"class":72},[66,1535,1536,1538,1540],{"class":68,"line":204},[66,1537,902],{"class":72},[66,1539,1455],{"class":76},[66,1541,80],{"class":72},[66,1543,1544,1546,1548],{"class":68,"line":211},[66,1545,115],{"class":72},[66,1547,77],{"class":76},[66,1549,80],{"class":72},[66,1551,1552],{"class":68,"line":369},[66,1553,126],{"emptyLinePlaceholder":125},[66,1555,1556],{"class":68,"line":374},[66,1557,377],{"class":207},[66,1559,1560,1562,1565,1568,1571,1573,1575,1578,1580],{"class":68,"line":380},[66,1561,73],{"class":72},[66,1563,1564],{"class":76},"DataTable",[66,1566,1567],{"class":72}," :",[66,1569,1570],{"class":92},"data",[66,1572,96],{"class":72},[66,1574,100],{"class":99},[66,1576,1577],{"class":271},"users",[66,1579,100],{"class":99},[66,1581,80],{"class":72},[66,1583,1584],{"class":68,"line":1202},[66,1585,1586],{"class":271},"  \u003Ctemplate #row=\"{ row }\">\n",[66,1588,1589],{"class":68,"line":1228},[66,1590,1591],{"class":271},"    \u003Ctd>{{ row.name }}\u003C\u002Ftd>\n",[66,1593,1594],{"class":68,"line":1247},[66,1595,1596],{"class":271},"    \u003Ctd>{{ row.age }}\u003C\u002Ftd>\n",[66,1598,1599],{"class":68,"line":1257},[66,1600,1601],{"class":271},"  \u003C\u002Ftemplate>\n",[66,1603,1605,1607,1609],{"class":68,"line":1604},16,[66,1606,115],{"class":72},[66,1608,1564],{"class":76},[66,1610,80],{"class":72},[23,1612,1613],{},"这种模式广泛用于表格、列表、下拉框等需要定制渲染逻辑的组件。",[41,1615,1617],{"id":1616},"_2-具名插槽与默认插槽的组合","2. 具名插槽与默认插槽的组合",[23,1619,1620],{},"组件可以同时提供默认插槽和多个具名插槽，供父组件灵活填充。",[58,1622,1624],{"className":60,"code":1623,"language":12,"meta":62,"style":62},"\u003C!-- Layout 组件 -->\n\u003Cdiv class=\"layout\">\n  \u003Cheader>\u003Cslot name=\"header\" \u002F>\u003C\u002Fheader>\n  \u003Cmain>\u003Cslot \u002F>\u003C\u002Fmain>\n  \u003Cfooter>\u003Cslot name=\"footer\" \u002F>\u003C\u002Ffooter>\n\u003C\u002Fdiv>\n",[46,1625,1626,1631,1651,1656,1661,1666],{"__ignoreMap":62},[66,1627,1628],{"class":68,"line":69},[66,1629,1630],{"class":207},"\u003C!-- Layout 组件 -->\n",[66,1632,1633,1635,1637,1640,1642,1644,1647,1649],{"class":68,"line":83},[66,1634,73],{"class":72},[66,1636,986],{"class":76},[66,1638,1639],{"class":92}," class",[66,1641,96],{"class":72},[66,1643,100],{"class":99},[66,1645,1646],{"class":103},"layout",[66,1648,100],{"class":99},[66,1650,80],{"class":72},[66,1652,1653],{"class":68,"line":112},[66,1654,1655],{"class":271},"  \u003Cheader>\u003Cslot name=\"header\" \u002F>\u003C\u002Fheader>\n",[66,1657,1658],{"class":68,"line":122},[66,1659,1660],{"class":271},"  \u003Cmain>\u003Cslot \u002F>\u003C\u002Fmain>\n",[66,1662,1663],{"class":68,"line":129},[66,1664,1665],{"class":271},"  \u003Cfooter>\u003Cslot name=\"footer\" \u002F>\u003C\u002Ffooter>\n",[66,1667,1668,1670,1672],{"class":68,"line":142},[66,1669,115],{"class":72},[66,1671,986],{"class":76},[66,1673,80],{"class":72},[23,1675,1676,1677,1680,1681,31],{},"使用简化语法 ",[46,1678,1679],{},"#header"," 代替 ",[46,1682,1683],{},"v-slot:header",[41,1685,1687],{"id":1686},"_3-通过插槽-props-向父组件暴露子组件内部状态","3. 通过插槽 props 向父组件暴露子组件内部状态",[23,1689,1690,1691,1694],{},"除了渲染数据，还可以暴露方法或状态，让父组件能够控制子组件内部的某些行为。例如，一个可拖拽列表的插槽可以暴露 ",[46,1692,1693],{},"dragHandle"," 属性，父组件将指令绑定到某个元素上。",[36,1696,1698],{"id":1697},"六异步组件通信","六、异步组件通信",[23,1700,1701,1702,1705,1706,1709],{},"异步组件通过 ",[46,1703,1704],{},"defineAsyncComponent"," 定义，通常配合 ",[46,1707,1708],{},"Suspense"," 使用以管理加载状态。",[41,1711,44,1713,1715],{"id":1712},"_1-defineasynccomponent-基本用法",[46,1714,1704],{}," 基本用法",[58,1717,1719],{"className":437,"code":1718,"language":439,"meta":62,"style":62},"import { defineAsyncComponent } from \"vue\";\nconst AsyncComp = defineAsyncComponent(() => import(\".\u002FHeavyComponent.vue\"));\n",[46,1720,1721,1742],{"__ignoreMap":62},[66,1722,1723,1725,1727,1730,1732,1734,1736,1738,1740],{"class":68,"line":69},[66,1724,452],{"class":451},[66,1726,157],{"class":72},[66,1728,1729],{"class":271}," defineAsyncComponent",[66,1731,465],{"class":72},[66,1733,468],{"class":451},[66,1735,167],{"class":99},[66,1737,12],{"class":103},[66,1739,100],{"class":99},[66,1741,285],{"class":72},[66,1743,1744,1746,1749,1751,1753,1755,1757,1759,1762,1764,1766,1769,1771,1774],{"class":68,"line":83},[66,1745,146],{"class":145},[66,1747,1748],{"class":149}," AsyncComp",[66,1750,154],{"class":153},[66,1752,1729],{"class":267},[66,1754,321],{"class":271},[66,1756,961],{"class":72},[66,1758,663],{"class":145},[66,1760,1761],{"class":153}," import",[66,1763,321],{"class":271},[66,1765,100],{"class":99},[66,1767,1768],{"class":103},".\u002FHeavyComponent.vue",[66,1770,100],{"class":99},[66,1772,1773],{"class":271},"))",[66,1775,285],{"class":72},[41,1777,1779,1780,1782],{"id":1778},"_2-配合-suspense-的加载状态管理","2. 配合 ",[46,1781,1708],{}," 的加载状态管理",[23,1784,1785,1787,1788,1791],{},[46,1786,1708],{}," 组件可以等待多个异步组件或异步 ",[46,1789,1790],{},"setup()"," 完成后才渲染 fallback 内容。",[58,1793,1795],{"className":60,"code":1794,"language":12,"meta":62,"style":62},"\u003Ctemplate>\n  \u003CSuspense>\n    \u003Ctemplate #default>\n      \u003CAsyncComponent \u002F>\n    \u003C\u002Ftemplate>\n    \u003Ctemplate #fallback>\n      \u003Cdiv>Loading...\u003C\u002Fdiv>\n    \u003C\u002Ftemplate>\n  \u003C\u002FSuspense>\n\u003C\u002Ftemplate>\n",[46,1796,1797,1805,1813,1827,1836,1844,1857,1875,1883,1891],{"__ignoreMap":62},[66,1798,1799,1801,1803],{"class":68,"line":69},[66,1800,73],{"class":72},[66,1802,77],{"class":76},[66,1804,80],{"class":72},[66,1806,1807,1809,1811],{"class":68,"line":83},[66,1808,86],{"class":72},[66,1810,1708],{"class":76},[66,1812,80],{"class":72},[66,1814,1815,1817,1819,1822,1825],{"class":68,"line":112},[66,1816,888],{"class":72},[66,1818,77],{"class":76},[66,1820,1821],{"class":72}," #",[66,1823,1824],{"class":92},"default",[66,1826,80],{"class":72},[66,1828,1829,1831,1834],{"class":68,"line":122},[66,1830,1495],{"class":72},[66,1832,1833],{"class":76},"AsyncComponent",[66,1835,109],{"class":72},[66,1837,1838,1840,1842],{"class":68,"line":129},[66,1839,1529],{"class":72},[66,1841,77],{"class":76},[66,1843,80],{"class":72},[66,1845,1846,1848,1850,1852,1855],{"class":68,"line":142},[66,1847,888],{"class":72},[66,1849,77],{"class":76},[66,1851,1821],{"class":72},[66,1853,1854],{"class":92},"fallback",[66,1856,80],{"class":72},[66,1858,1859,1861,1863,1866,1869,1871,1873],{"class":68,"line":204},[66,1860,1495],{"class":72},[66,1862,986],{"class":76},[66,1864,1865],{"class":72},">",[66,1867,1868],{"class":271},"Loading...",[66,1870,115],{"class":72},[66,1872,986],{"class":76},[66,1874,80],{"class":72},[66,1876,1877,1879,1881],{"class":68,"line":211},[66,1878,1529],{"class":72},[66,1880,77],{"class":76},[66,1882,80],{"class":72},[66,1884,1885,1887,1889],{"class":68,"line":369},[66,1886,902],{"class":72},[66,1888,1708],{"class":76},[66,1890,80],{"class":72},[66,1892,1893,1895,1897],{"class":68,"line":374},[66,1894,115],{"class":72},[66,1896,77],{"class":76},[66,1898,80],{"class":72},[23,1900,1901,1902,1904,1905,1908,1909,1911],{},"在异步组件内部，如果 ",[46,1903,1353],{}," 返回一个 Promise 或者使用了顶层 ",[46,1906,1907],{},"await","，",[46,1910,1708],{}," 会自动捕获并展示 fallback。",[41,1913,1915],{"id":1914},"_3-通信注意事项","3. 通信注意事项",[774,1917,1918,1935,1942],{},[777,1919,1920,1921,1923,1924,1926,1927,1930,1931,1934],{},"异步组件在加载完成后才创建实例，因此父组件通过 ",[46,1922,405],{}," 引用异步组件时，需要等待 ",[46,1925,1708],{}," 的 ",[46,1928,1929],{},"onResolve"," 或者使用 ",[46,1932,1933],{},"watch"," 监听组件实例是否就绪。",[777,1936,1937,1938,1941],{},"通过 provide\u002Finject 传递响应式数据时，异步组件仍能正常接收，只要在注入时组件已经 mounted（或者通过 ",[46,1939,1940],{},"watchEffect"," 处理初始值）。",[777,1943,1944],{},"尽量避免在异步组件的插槽中依赖父组件的同步状态，因为渲染顺序可能导致不一致。",[36,1946,1948],{"id":1947},"七总结","七、总结",[1455,1950,1951,1966],{},[1952,1953,1954],"thead",{},[1464,1955,1956,1960,1963],{},[1957,1958,1959],"th",{},"通信模式",[1957,1961,1962],{},"适用场景",[1957,1964,1965],{},"关键 API \u002F 特性",[1967,1968,1969,1991,2009,2024,2038,2051],"tbody",{},[1464,1970,1971,1977,1980],{},[1972,1973,1974],"td",{},[792,1975,1976],{},"Props + Emit",[1972,1978,1979],{},"父子组件直接通信",[1972,1981,1982,1984,1985,1984,1987,1990],{},[46,1983,55],{},"、",[46,1986,234],{},[46,1988,1989],{},"v-model","、单向数据流",[1464,1992,1993,1997,2000],{},[1972,1994,1995],{},[792,1996,794],{},[1972,1998,1999],{},"跨越多层级的组件树内共享，非全局",[1972,2001,2002,1984,2004,1984,2006,2008],{},[46,2003,415],{},[46,2005,419],{},[46,2007,584],{},"、函数注入",[1464,2010,2011,2015,2018],{},[1972,2012,2013],{},[792,2014,223],{},[1972,2016,2017],{},"高阶组件透传未声明的属性和事件",[1972,2019,2020,1984,2022],{},[46,2021,920],{},[46,2023,930],{},[1464,2025,2026,2030,2033],{},[1972,2027,2028],{},[792,2029,1031],{},[1972,2031,2032],{},"直接访问子组件实例或 DOM",[1972,2034,2035,2036],{},"模板 ref、",[46,2037,1357],{},[1464,2039,2040,2045,2048],{},[1972,2041,2042],{},[792,2043,2044],{},"插槽",[1972,2046,2047],{},"定制组件内容，作用域插槽可用于数据回传",[1972,2049,2050],{},"默认插槽、具名插槽、作用域插槽",[1464,2052,2053,2058,2061],{},[1972,2054,2055],{},[792,2056,2057],{},"异步组件 + Suspense",[1972,2059,2060],{},"代码分割、加载状态管理",[1972,2062,2063,1984,2065],{},[46,2064,1704],{},[46,2066,1708],{},[23,2068,2069,2070,2073,2074,2076,2077,2080,2081,31],{},"在实际开发中，应优先使用 ",[792,2071,2072],{},"props + emit"," 保持组件接口清晰；当层次过深导致 prop drilling 时，考虑 ",[792,2075,794],{},"；对于需要高度自定义渲染逻辑的组件，使用 ",[792,2078,2079],{},"作用域插槽","；跨页面\u002F全局共享状态用 ",[27,2082,2084],{"href":2083},"\u002Fknowledge\u002Fbooklet\u002Fframe\u002Fvue\u002Fstatus","Pinia",[2086,2087,2088],"h2",{"id":2088},"参考文献",[23,2090,2091],{},"以下链接在编写时均可正常访问：",[1455,2093,2094,2104],{},[1952,2095,2096],{},[1464,2097,2098,2101],{},[1957,2099,2100],{},"资料",[1957,2102,2103],{},"说明",[1967,2105,2106,2119,2130,2142],{},[1464,2107,2108,2116],{},[1972,2109,2110],{},[27,2111,2115],{"href":2112,"rel":2113},"https:\u002F\u002Fcn.vuejs.org\u002Fguide\u002Fcomponents\u002Fprops.html",[2114],"nofollow","Vue：Props",[1972,2117,2118],{},"单向数据流",[1464,2120,2121,2128],{},[1972,2122,2123],{},[27,2124,2127],{"href":2125,"rel":2126},"https:\u002F\u002Fcn.vuejs.org\u002Fguide\u002Fcomponents\u002Fevents.html",[2114],"Vue：组件事件",[1972,2129,234],{},[1464,2131,2132,2139],{},[1972,2133,2134],{},[27,2135,2138],{"href":2136,"rel":2137},"https:\u002F\u002Fcn.vuejs.org\u002Fguide\u002Fcomponents\u002Fprovide-inject.html",[2114],"Vue：provide \u002F inject",[1972,2140,2141],{},"跨层级",[1464,2143,2144,2151],{},[1972,2145,2146],{},[27,2147,2150],{"href":2148,"rel":2149},"https:\u002F\u002Fcn.vuejs.org\u002Fguide\u002Fcomponents\u002Fslots.html",[2114],"Vue：插槽",[1972,2152,2044],{},[2154,2155,2156],"style",{},"html pre.shiki code .sP7_E, html code.shiki .sP7_E{--shiki-light:#39ADB5;--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sQzsp, html code.shiki .sQzsp{--shiki-light:#E53935;--shiki-default:#22863A;--shiki-dark:#85E89D}html pre.shiki code .s9AJx, html code.shiki .s9AJx{--shiki-light:#9C3EDA;--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sjJ54, html code.shiki .sjJ54{--shiki-light:#39ADB5;--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .s_sjI, html code.shiki .s_sjI{--shiki-light:#91B859;--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .sbsja, html code.shiki .sbsja{--shiki-light:#9C3EDA;--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .s_hVV, html code.shiki .s_hVV{--shiki-light:#90A4AE;--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .smGrS, html code.shiki .smGrS{--shiki-light:#39ADB5;--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .skxfh, html code.shiki .skxfh{--shiki-light:#E53935;--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .srdBf, html code.shiki .srdBf{--shiki-light:#F76D47;--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sutJx, html code.shiki .sutJx{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#6A737D;--shiki-default-font-style:inherit;--shiki-dark:#6A737D;--shiki-dark-font-style:inherit}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sGLFI, html code.shiki .sGLFI{--shiki-light:#6182B8;--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .su5hD, html code.shiki .su5hD{--shiki-light:#90A4AE;--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .s99_P, html code.shiki .s99_P{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#E36209;--shiki-default-font-style:inherit;--shiki-dark:#FFAB70;--shiki-dark-font-style:inherit}html pre.shiki code .sVHd0, html code.shiki .sVHd0{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#D73A49;--shiki-default-font-style:inherit;--shiki-dark:#F97583;--shiki-dark-font-style:inherit}html pre.shiki code .sfCm-, html code.shiki .sfCm-{--shiki-light:#90A4AE;--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .svtyB, html code.shiki .svtyB{--shiki-light:#39ADB5;--shiki-light-font-style:inherit;--shiki-default:#B31D28;--shiki-default-font-style:italic;--shiki-dark:#FDAEB7;--shiki-dark-font-style:italic}html pre.shiki code .s39Yj, html code.shiki .s39Yj{--shiki-light:#39ADB5;--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sbgvK, html code.shiki .sbgvK{--shiki-light:#E2931D;--shiki-default:#6F42C1;--shiki-dark:#B392F0}",{"title":62,"searchDepth":83,"depth":83,"links":2158},[2159,2160,2161,2163,2165,2166,2167,2168],{"id":38,"depth":112,"text":39},{"id":409,"depth":112,"text":410},{"id":814,"depth":112,"text":2162},"三、$attrs 与透传",{"id":1027,"depth":112,"text":2164},"四、$refs 与组件实例引用",{"id":1408,"depth":112,"text":1409},{"id":1697,"depth":112,"text":1698},{"id":1947,"depth":112,"text":1948},{"id":2088,"depth":83,"text":2088},{"title":8,"description":9},"knowledge\u002Fbooklet\u002Fframe\u002FVue\u002Fprops","knowledge\u002Fknowledge\u002Fbooklet\u002Fframe\u002FVue\u002Fprops.md","md",{"items":2174},[2175,2179,2182,2186,2190,2194],{"path":2176,"title":2177,"description":2178,"category":10,"score":142},"\u002Fknowledge\u002Fbooklet\u002Fframe\u002Fvue\u002Fperformance\u002Fassets","资源优化","图片懒加载、按需引入与 Web Vitals 监控。见 HTML 图片、CSS 字体优化。",{"path":2083,"title":2180,"description":2181,"category":10,"score":142},"状态管理：Pinia 与 Vuex","Pinia 是 Vue 官方推荐的状态管理库（Vue 3 新项目默认选型）。Vuex 4 仍可与 Vue 3 配合，用于维护旧项目。见 Vue 基础。",{"path":2183,"title":2184,"description":2185,"category":10,"score":142},"\u002Fknowledge\u002Fbooklet\u002Fframe\u002Fvue\u002Fecology","Vue 生态关键库深度集成","VueUse、Vite 与 Nuxt 是 Vue 3 生态中常用的效率与工程化方案。概览见 Vue 基础。",{"path":2187,"title":2188,"description":2189,"category":10,"score":142},"\u002Fknowledge\u002Fbooklet\u002Fframe\u002Fvue\u002Freactivity\u002Ftrack","依赖收集与派发更新机制","说明 Vue 3 中 track \u002F trigger 与 targetMap 的工作方式。前置：v2-v3 差异。",{"path":2191,"title":2192,"description":2193,"category":10,"score":142},"\u002Fknowledge\u002Fbooklet\u002Fframe\u002Fvue\u002Ftest","测试策略","Vue 应用常用 Vitest + @vue\u002Ftest-utils 做单元\u002F组件测试，Playwright 或 Cypress 做 E2E。见 Vue 基础。",{"path":2195,"title":2196,"description":2197,"category":10,"score":142},"\u002Fknowledge\u002Fbooklet\u002Fframe\u002Fvue\u002Fdesign","组合式 API 与逻辑复用设计模式","组合式 API 与 Composables 是 Vue 3 推荐的逻辑组织方式。概览见 Vue 基础。",{"series":2199,"title":12,"items":2200,"index":142,"prev":2248,"next":2249},"booklet\u002Fframe\u002Fvue",[2201,2203,2205,2209,2211,2213,2217,2218,2222,2226,2230,2234,2236,2238,2240,2244],{"path":2176,"title":2177,"date":2202,"pinned":15},"2025-11-06",{"path":29,"title":30,"date":2204,"pinned":15},"2021-07-29",{"path":2206,"title":2207,"date":2208,"pinned":15},"\u002Fknowledge\u002Fbooklet\u002Fframe\u002Fvue\u002Fperformance\u002Fbuild","编译与打包优化","2021-08-02",{"path":2195,"title":2196,"date":2210,"pinned":15},"2024-06-16",{"path":2183,"title":2184,"date":2212,"pinned":15},"2025-08-26",{"path":2214,"title":2215,"date":2216,"pinned":15},"\u002Fknowledge\u002Fbooklet\u002Fframe\u002Fvue\u002Fproject","工程化实践","2021-07-20",{"path":7,"title":8,"date":14,"pinned":15},{"path":2219,"title":2220,"date":2221,"pinned":15},"\u002Fknowledge\u002Fbooklet\u002Fframe\u002Fvue\u002Freactivity\u002Fproxy","响应式进阶","2023-03-21",{"path":2223,"title":2224,"date":2225,"pinned":15},"\u002Fknowledge\u002Fbooklet\u002Fframe\u002Fvue\u002Frender","渲染机制与编译原理","2021-09-23",{"path":2227,"title":2228,"date":2229,"pinned":15},"\u002Fknowledge\u002Fbooklet\u002Fframe\u002Fvue\u002Frouter","路由与权限控制","2021-09-12",{"path":2231,"title":2232,"date":2233,"pinned":15},"\u002Fknowledge\u002Fbooklet\u002Fframe\u002Fvue\u002Fperformance\u002Fruntime","运行时优化","2021-06-10",{"path":2083,"title":2180,"date":2235,"pinned":15},"2025-10-11",{"path":2191,"title":2192,"date":2237,"pinned":15},"2024-10-23",{"path":2187,"title":2188,"date":2239,"pinned":15},"2025-01-13",{"path":2241,"title":2242,"date":2243,"pinned":15},"\u002Fknowledge\u002Fbooklet\u002Fframe\u002Fvue\u002Ftypescript","TypeScript 深度集成","2023-11-29",{"path":2245,"title":2246,"date":2247,"pinned":15},"\u002Fknowledge\u002Fbooklet\u002Fframe\u002Fvue\u002Freactivity\u002Fv2-v3","Vue 2 与 Vue 3 响应式差异","2022-07-06",{"path":2214,"title":2215,"date":2216,"pinned":15},{"path":2219,"title":2220,"date":2221,"pinned":15}]