[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"knowledge-\u002Fapi\u002Fknowledge\u002Fbooklet\u002Fframe\u002Fvue\u002Frender":3,"knowledge-related-\u002Fknowledge\u002Fbooklet\u002Fframe\u002Fvue\u002Frender":1953,"knowledge-series-\u002Fknowledge\u002Fbooklet\u002Fframe\u002Fvue\u002Frender":1979},{"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":1949,"stem":1950,"id":1951,"extension":1952},"\u002Fknowledge\u002Fbooklet\u002Fframe\u002Fvue\u002Frender","渲染机制与编译原理","Vue 的渲染由编译时（模板 → render）与运行时（VNode → DOM）组成。见 Vue 基础。","技能小册",[12,13],"vue","render","2021-09-23",false,{"type":17,"value":18,"toc":1939},"minimark",[19,22,41,50,55,77,82,89,366,370,373,400,472,476,493,617,630,634,641,645,652,771,777,781,788,909,915,982,986,992,1016,1067,1076,1080,1165,1175,1183,1189,1192,1202,1224,1419,1425,1445,1449,1452,1620,1624,1780,1803,1806,1875,1878,1882,1885,1935],[20,21,8],"h1",{"id":8},[23,24,25,26,30,31,34,35,40],"p",{},"Vue 的渲染由",[27,28,29],"strong",{},"编译时","（模板 → render）与",[27,32,33],{},"运行时","（VNode → DOM）组成。见 ",[36,37,39],"a",{"href":38},"\u002Fknowledge\u002Fbooklet\u002Fframe\u002Fvue\u002Fbasics","Vue 基础","。",[23,42,43,44,46,47,49],{},"Vue 的渲染系统由",[27,45,29],{},"（模板 → render 函数）和",[27,48,33],{},"（虚拟 DOM → 真实 DOM）两部分组成。理解其内部机制，有助于写出高性能代码，甚至扩展 Vue 到不同平台。",[51,52,54],"h3",{"id":53},"_1-模板编译三部曲template-parser-ast-转换-codegen-生成-render-函数","1. 模板编译三部曲：Template Parser → AST 转换 → CodeGen 生成 Render 函数",[23,56,57,58,62,63,66,67,69,70,73,74,40],{},"Vue 单文件组件（",[59,60,61],"code",{},".vue","）中的 ",[59,64,65],{},"\u003Ctemplate>"," 会被编译成 ",[59,68,13],{}," 函数，整个过程分为三个阶段，出自 ",[59,71,72],{},"@vue\u002Fcompiler-dom"," 与 ",[59,75,76],{},"@vue\u002Fcompiler-core",[78,79,81],"h4",{"id":80},"第一步模板解析parser","第一步：模板解析（Parser）",[23,83,84,85,88],{},"将模板字符串转换为",[27,86,87],{},"抽象语法树（AST）","。解析器使用有限状态机（Finite State Machine）逐个字符读取模板，识别开始标签、结束标签、文本、插值表达式、指令等，生成 AST 节点树。",[90,91,96],"pre",{"className":92,"code":93,"language":94,"meta":95,"style":95},"language-js shiki shiki-themes material-theme-lighter github-light github-dark","\u002F\u002F 模板\n\u003Cdiv class=\"container\">Hello {{ name }}\u003C\u002Fdiv>\n\n\u002F\u002F 简化后的 AST 节点\n{\n  type: 1,  \u002F\u002F NodeTypes.ELEMENT\n  tag: 'div',\n  props: [{ name: 'class', value: { content: 'container' } }],\n  children: [\n    { type: 2, content: 'Hello ' },   \u002F\u002F NodeTypes.TEXT\n    { type: 5, content: { content: 'name' } } \u002F\u002F NodeTypes.INTERPOLATION\n  ]\n}\n","js","",[59,97,98,107,157,164,170,176,196,215,273,284,316,354,360],{"__ignoreMap":95},[99,100,103],"span",{"class":101,"line":102},"line",1,[99,104,106],{"class":105},"sutJx","\u002F\u002F 模板\n",[99,108,110,114,118,122,126,130,134,136,139,143,146,149,152,154],{"class":101,"line":109},2,[99,111,113],{"class":112},"sP7_E","\u003C",[99,115,117],{"class":116},"sQzsp","div",[99,119,121],{"class":120},"s9AJx"," class",[99,123,125],{"class":124},"smGrS","=",[99,127,129],{"class":128},"sjJ54","\"",[99,131,133],{"class":132},"s_sjI","container",[99,135,129],{"class":128},[99,137,138],{"class":112},">",[99,140,142],{"class":141},"su5hD","Hello ",[99,144,145],{"class":112},"{{",[99,147,148],{"class":141}," name ",[99,150,151],{"class":112},"}}\u003C\u002F",[99,153,117],{"class":116},[99,155,156],{"class":112},">\n",[99,158,160],{"class":101,"line":159},3,[99,161,163],{"emptyLinePlaceholder":162},true,"\n",[99,165,167],{"class":101,"line":166},4,[99,168,169],{"class":105},"\u002F\u002F 简化后的 AST 节点\n",[99,171,173],{"class":101,"line":172},5,[99,174,175],{"class":112},"{\n",[99,177,179,183,186,190,193],{"class":101,"line":178},6,[99,180,182],{"class":181},"sbgvK","  type",[99,184,185],{"class":112},":",[99,187,189],{"class":188},"srdBf"," 1",[99,191,192],{"class":112},",",[99,194,195],{"class":105},"  \u002F\u002F NodeTypes.ELEMENT\n",[99,197,199,202,204,207,209,212],{"class":101,"line":198},7,[99,200,201],{"class":181},"  tag",[99,203,185],{"class":112},[99,205,206],{"class":128}," '",[99,208,117],{"class":132},[99,210,211],{"class":128},"'",[99,213,214],{"class":112},",\n",[99,216,218,221,223,227,230,233,235,237,240,242,244,247,249,252,255,257,259,261,263,266,268,271],{"class":101,"line":217},8,[99,219,220],{"class":181},"  props",[99,222,185],{"class":112},[99,224,226],{"class":225},"skxfh"," [",[99,228,229],{"class":112},"{",[99,231,232],{"class":225}," name",[99,234,185],{"class":112},[99,236,206],{"class":128},[99,238,239],{"class":132},"class",[99,241,211],{"class":128},[99,243,192],{"class":112},[99,245,246],{"class":225}," value",[99,248,185],{"class":112},[99,250,251],{"class":112}," {",[99,253,254],{"class":225}," content",[99,256,185],{"class":112},[99,258,206],{"class":128},[99,260,133],{"class":132},[99,262,211],{"class":128},[99,264,265],{"class":112}," }",[99,267,265],{"class":112},[99,269,270],{"class":225},"]",[99,272,214],{"class":112},[99,274,276,279,281],{"class":101,"line":275},9,[99,277,278],{"class":181},"  children",[99,280,185],{"class":112},[99,282,283],{"class":225}," [\n",[99,285,287,290,293,295,298,300,302,304,306,308,310,313],{"class":101,"line":286},10,[99,288,289],{"class":112},"    {",[99,291,292],{"class":225}," type",[99,294,185],{"class":112},[99,296,297],{"class":188}," 2",[99,299,192],{"class":112},[99,301,254],{"class":225},[99,303,185],{"class":112},[99,305,206],{"class":128},[99,307,142],{"class":132},[99,309,211],{"class":128},[99,311,312],{"class":112}," },",[99,314,315],{"class":105},"   \u002F\u002F NodeTypes.TEXT\n",[99,317,319,321,323,325,328,330,332,334,336,338,340,342,345,347,349,351],{"class":101,"line":318},11,[99,320,289],{"class":112},[99,322,292],{"class":225},[99,324,185],{"class":112},[99,326,327],{"class":188}," 5",[99,329,192],{"class":112},[99,331,254],{"class":225},[99,333,185],{"class":112},[99,335,251],{"class":112},[99,337,254],{"class":225},[99,339,185],{"class":112},[99,341,206],{"class":128},[99,343,344],{"class":132},"name",[99,346,211],{"class":128},[99,348,265],{"class":112},[99,350,265],{"class":112},[99,352,353],{"class":105}," \u002F\u002F NodeTypes.INTERPOLATION\n",[99,355,357],{"class":101,"line":356},12,[99,358,359],{"class":225},"  ]\n",[99,361,363],{"class":101,"line":362},13,[99,364,365],{"class":112},"}\n",[78,367,369],{"id":368},"第二步ast-转换transform","第二步：AST 转换（Transform）",[23,371,372],{},"遍历 AST，进行一系列优化和转换：",[374,375,376,391,394,397],"ul",{},[377,378,379,380,383,384,383,387,390],"li",{},"解析指令（",[59,381,382],{},"v-if","、",[59,385,386],{},"v-for",[59,388,389],{},"v-on"," 等）并生成对应代码结构。",[377,392,393],{},"识别静态节点并标记（用于后续静态提升）。",[377,395,396],{},"处理插槽、作用域插槽。",[377,398,399],{},"计算 PatchFlag、动态属性列表等（Vue 3 编译优化核心）。",[90,401,403],{"className":92,"code":402,"language":94,"meta":95,"style":95},"\u002F\u002F 经过 transform 后，动态节点被标记\n{\n  tag: 'div',\n  patchFlag: 1 \u002F* TEXT *\u002F,   \u002F\u002F 表示该节点文本动态变化\n  dynamicProps: ['class']?   \u002F\u002F 若有动态属性会列出\n}\n",[59,404,405,410,414,428,445,468],{"__ignoreMap":95},[99,406,407],{"class":101,"line":102},[99,408,409],{"class":105},"\u002F\u002F 经过 transform 后，动态节点被标记\n",[99,411,412],{"class":101,"line":109},[99,413,175],{"class":112},[99,415,416,418,420,422,424,426],{"class":101,"line":159},[99,417,201],{"class":181},[99,419,185],{"class":112},[99,421,206],{"class":128},[99,423,117],{"class":132},[99,425,211],{"class":128},[99,427,214],{"class":112},[99,429,430,433,435,437,440,442],{"class":101,"line":166},[99,431,432],{"class":181},"  patchFlag",[99,434,185],{"class":112},[99,436,189],{"class":188},[99,438,439],{"class":105}," \u002F* TEXT *\u002F",[99,441,192],{"class":112},[99,443,444],{"class":105},"   \u002F\u002F 表示该节点文本动态变化\n",[99,446,447,450,452,454,456,458,460,462,465],{"class":101,"line":172},[99,448,449],{"class":181},"  dynamicProps",[99,451,185],{"class":112},[99,453,226],{"class":225},[99,455,211],{"class":128},[99,457,239],{"class":132},[99,459,211],{"class":128},[99,461,270],{"class":225},[99,463,464],{"class":124},"?",[99,466,467],{"class":105},"   \u002F\u002F 若有动态属性会列出\n",[99,469,470],{"class":101,"line":178},[99,471,365],{"class":225},[78,473,475],{"id":474},"第三步代码生成codegen","第三步：代码生成（CodeGen）",[23,477,478,479,481,482,485,486,488,489,492],{},"根据转换后的 AST 生成 ",[59,480,13],{}," 函数的代码字符串（或直接生成 ",[59,483,484],{},"function","）。最终输出一个 ",[59,487,13],{}," 函数，内部调用 ",[59,490,491],{},"h","（createVNode）函数来构建虚拟节点。",[90,494,496],{"className":92,"code":495,"language":94,"meta":95,"style":95},"\u002F\u002F 生成的 render 函数（简化）\nfunction render(_ctx, _cache) {\n  return (\n    _openBlock(),\n    _createElementBlock(\"div\", { class: \"container\" }, [\"Hello \" + _toDisplayString(_ctx.name)])\n  );\n}\n",[59,497,498,503,530,539,549,605,613],{"__ignoreMap":95},[99,499,500],{"class":101,"line":102},[99,501,502],{"class":105},"\u002F\u002F 生成的 render 函数（简化）\n",[99,504,505,508,512,515,519,521,524,527],{"class":101,"line":109},[99,506,484],{"class":507},"sbsja",[99,509,511],{"class":510},"sGLFI"," render",[99,513,514],{"class":112},"(",[99,516,518],{"class":517},"s99_P","_ctx",[99,520,192],{"class":112},[99,522,523],{"class":517}," _cache",[99,525,526],{"class":112},")",[99,528,529],{"class":112}," {\n",[99,531,532,536],{"class":101,"line":159},[99,533,535],{"class":534},"sVHd0","  return",[99,537,538],{"class":225}," (\n",[99,540,541,544,547],{"class":101,"line":166},[99,542,543],{"class":510},"    _openBlock",[99,545,546],{"class":225},"()",[99,548,214],{"class":112},[99,550,551,554,556,558,560,562,564,566,568,570,573,575,577,579,581,583,585,587,590,593,595,597,600,602],{"class":101,"line":172},[99,552,553],{"class":510},"    _createElementBlock",[99,555,514],{"class":225},[99,557,129],{"class":128},[99,559,117],{"class":132},[99,561,129],{"class":128},[99,563,192],{"class":112},[99,565,251],{"class":112},[99,567,121],{"class":225},[99,569,185],{"class":112},[99,571,572],{"class":128}," \"",[99,574,133],{"class":132},[99,576,129],{"class":128},[99,578,312],{"class":112},[99,580,226],{"class":225},[99,582,129],{"class":128},[99,584,142],{"class":132},[99,586,129],{"class":128},[99,588,589],{"class":124}," +",[99,591,592],{"class":510}," _toDisplayString",[99,594,514],{"class":225},[99,596,518],{"class":141},[99,598,599],{"class":112},".",[99,601,344],{"class":141},[99,603,604],{"class":225},")])\n",[99,606,607,610],{"class":101,"line":178},[99,608,609],{"class":225},"  )",[99,611,612],{"class":112},";\n",[99,614,615],{"class":101,"line":198},[99,616,365],{"class":112},[23,618,619,620,383,623,383,626,629],{},"对于 Vue 3，编译结果通常包含 ",[59,621,622],{},"_createElementBlock",[59,624,625],{},"_createElementVNode",[59,627,628],{},"_openBlock"," 等辅助函数。",[51,631,633],{"id":632},"_2-虚拟-dom-的-diff-算法vue-3-优化版","2. 虚拟 DOM 的 Diff 算法（Vue 3 优化版）",[23,635,636,637,640],{},"Vue 3 在保留虚拟 DOM 灵活性的前提下，通过编译时信息大幅提升了 ",[59,638,639],{},"patch"," 过程的效率。",[78,642,644],{"id":643},"核心优化一静态提升static-hoisting","核心优化一：静态提升（Static Hoisting）",[23,646,647,648,651],{},"编译时会将",[27,649,650],{},"纯静态的节点","（不依赖任何动态数据）提升到渲染函数外部，使得它们只在应用启动时创建一次，每次渲染复用同一个 VNode 对象。",[90,653,655],{"className":92,"code":654,"language":94,"meta":95,"style":95},"\u002F\u002F 编译前\n\u003Cdiv>static text\u003C\u002Fdiv>;\n\n\u002F\u002F 编译后\nconst _hoisted_1 = \u002F*#__PURE__*\u002F _createElementVNode(\"div\", null, \"static text\", -1 \u002F* HOISTED *\u002F);\n\nfunction render() {\n  return _hoisted_1;\n}\n",[59,656,657,662,681,685,690,745,749,759,767],{"__ignoreMap":95},[99,658,659],{"class":101,"line":102},[99,660,661],{"class":105},"\u002F\u002F 编译前\n",[99,663,664,666,668,670,673,676,678],{"class":101,"line":109},[99,665,113],{"class":112},[99,667,117],{"class":116},[99,669,138],{"class":112},[99,671,672],{"class":141},"static text",[99,674,675],{"class":112},"\u003C\u002F",[99,677,117],{"class":116},[99,679,680],{"class":112},">;\n",[99,682,683],{"class":101,"line":159},[99,684,163],{"emptyLinePlaceholder":162},[99,686,687],{"class":101,"line":166},[99,688,689],{"class":105},"\u002F\u002F 编译后\n",[99,691,692,695,699,702,705,708,710,712,714,716,718,722,724,726,728,730,732,735,738,741,743],{"class":101,"line":172},[99,693,694],{"class":507},"const",[99,696,698],{"class":697},"s_hVV"," _hoisted_1",[99,700,701],{"class":124}," =",[99,703,704],{"class":105}," \u002F*#__PURE__*\u002F",[99,706,707],{"class":510}," _createElementVNode",[99,709,514],{"class":141},[99,711,129],{"class":128},[99,713,117],{"class":132},[99,715,129],{"class":128},[99,717,192],{"class":112},[99,719,721],{"class":720},"s39Yj"," null",[99,723,192],{"class":112},[99,725,572],{"class":128},[99,727,672],{"class":132},[99,729,129],{"class":128},[99,731,192],{"class":112},[99,733,734],{"class":124}," -",[99,736,737],{"class":188},"1",[99,739,740],{"class":105}," \u002F* HOISTED *\u002F",[99,742,526],{"class":141},[99,744,612],{"class":112},[99,746,747],{"class":101,"line":178},[99,748,163],{"emptyLinePlaceholder":162},[99,750,751,753,755,757],{"class":101,"line":198},[99,752,484],{"class":507},[99,754,511],{"class":510},[99,756,546],{"class":112},[99,758,529],{"class":112},[99,760,761,763,765],{"class":101,"line":217},[99,762,535],{"class":534},[99,764,698],{"class":141},[99,766,612],{"class":112},[99,768,769],{"class":101,"line":275},[99,770,365],{"class":112},[23,772,773,776],{},[27,774,775],{},"收益","：减少重复创建 VNode 的内存和时间开销。",[78,778,780],{"id":779},"核心优化二patchflag-精准标记动态节点类型","核心优化二：PatchFlag 精准标记动态节点类型",[23,782,783,784,787],{},"在编译时为每个节点标记一个 ",[59,785,786],{},"patchFlag"," 位掩码，告诉运行时在更新时只需要检查哪些类型的变更。",[789,790,791,807],"table",{},[792,793,794],"thead",{},[795,796,797,801,804],"tr",{},[798,799,800],"th",{},"PatchFlag 值",[798,802,803],{},"含义",[798,805,806],{},"描述",[808,809,810,821,832,843,854,865,876,887,898],"tbody",{},[795,811,812,815,818],{},[813,814,737],"td",{},[813,816,817],{},"TEXT",[813,819,820],{},"文本内容动态变化",[795,822,823,826,829],{},[813,824,825],{},"2",[813,827,828],{},"CLASS",[813,830,831],{},"class 绑定动态变化",[795,833,834,837,840],{},[813,835,836],{},"4",[813,838,839],{},"STYLE",[813,841,842],{},"style 绑定动态变化",[795,844,845,848,851],{},[813,846,847],{},"8",[813,849,850],{},"PROPS",[813,852,853],{},"其他属性动态变化",[795,855,856,859,862],{},[813,857,858],{},"16",[813,860,861],{},"FULL_PROPS",[813,863,864],{},"需要完整 diff props（动态 key）",[795,866,867,870,873],{},[813,868,869],{},"32",[813,871,872],{},"HYDRATE_EVENTS",[813,874,875],{},"事件监听器需要 hydrating（SSR 专用）",[795,877,878,881,884],{},[813,879,880],{},"64",[813,882,883],{},"STABLE_FRAGMENT",[813,885,886],{},"子节点顺序稳定（可简化 diff）",[795,888,889,892,895],{},[813,890,891],{},"128",[813,893,894],{},"KEYED_FRAGMENT",[813,896,897],{},"带 key 的 fragment",[795,899,900,903,906],{},[813,901,902],{},"256",[813,904,905],{},"UNKEYED_FRAGMENT",[813,907,908],{},"不带 key 的 fragment",[23,910,911,912,914],{},"Diff 时，根据 ",[59,913,786],{}," 跳过不必要的遍历：",[90,916,918],{"className":92,"code":917,"language":94,"meta":95,"style":95},"if (patchFlag & PatchFlags.TEXT) {\n  \u002F\u002F 只对比文本内容\n} else if (patchFlag & PatchFlags.PROPS) {\n  \u002F\u002F 只对比 props 中指定的动态属性\n}\n",[59,919,920,943,948,973,978],{"__ignoreMap":95},[99,921,922,925,928,931,934,936,938,941],{"class":101,"line":102},[99,923,924],{"class":534},"if",[99,926,927],{"class":141}," (patchFlag ",[99,929,930],{"class":124},"&",[99,932,933],{"class":141}," PatchFlags",[99,935,599],{"class":112},[99,937,817],{"class":697},[99,939,940],{"class":141},") ",[99,942,175],{"class":112},[99,944,945],{"class":101,"line":109},[99,946,947],{"class":105},"  \u002F\u002F 只对比文本内容\n",[99,949,950,953,956,959,961,963,965,967,969,971],{"class":101,"line":159},[99,951,952],{"class":112},"}",[99,954,955],{"class":534}," else",[99,957,958],{"class":534}," if",[99,960,927],{"class":141},[99,962,930],{"class":124},[99,964,933],{"class":141},[99,966,599],{"class":112},[99,968,850],{"class":697},[99,970,940],{"class":141},[99,972,175],{"class":112},[99,974,975],{"class":101,"line":166},[99,976,977],{"class":105},"  \u002F\u002F 只对比 props 中指定的动态属性\n",[99,979,980],{"class":101,"line":172},[99,981,365],{"class":112},[78,983,985],{"id":984},"核心优化三块树block-tree结构","核心优化三：块树（Block Tree）结构",[23,987,988,991],{},[27,989,990],{},"问题","：传统虚拟 DOM 的 Diff 需要递归遍历整个树，即使很多节点是静态的。",[23,993,994,997,998,1001,1002,383,1004,383,1006,1008,1009,1011,1012,1015],{},[27,995,996],{},"解决","：Vue 3 引入 ",[59,999,1000],{},"Block"," 概念。编译器将带有结构指令（",[59,1003,382],{},[59,1005,386],{},[59,1007,386],{}," 内部的动态节点等）的节点收集到一个扁平数组中。每个 ",[59,1010,1000],{}," 维护一个 ",[59,1013,1014],{},"dynamicChildren"," 列表，仅包含动态节点。",[90,1017,1019],{"className":92,"code":1018,"language":94,"meta":95,"style":95},"\u002F\u002F 渲染时\n_openBlock();   \u002F\u002F 开启 Block\n_createElementBlock(\"div\", ...); \u002F\u002F 创建 Block 根节点\n\u002F\u002F 内部动态节点都会被收集到 Block 的 dynamicChildren 中\n",[59,1020,1021,1026,1038,1062],{"__ignoreMap":95},[99,1022,1023],{"class":101,"line":102},[99,1024,1025],{"class":105},"\u002F\u002F 渲染时\n",[99,1027,1028,1030,1032,1035],{"class":101,"line":109},[99,1029,628],{"class":510},[99,1031,546],{"class":141},[99,1033,1034],{"class":112},";",[99,1036,1037],{"class":105},"   \u002F\u002F 开启 Block\n",[99,1039,1040,1042,1044,1046,1048,1050,1052,1055,1057,1059],{"class":101,"line":159},[99,1041,622],{"class":510},[99,1043,514],{"class":141},[99,1045,129],{"class":128},[99,1047,117],{"class":132},[99,1049,129],{"class":128},[99,1051,192],{"class":112},[99,1053,1054],{"class":124}," ...",[99,1056,526],{"class":141},[99,1058,1034],{"class":112},[99,1060,1061],{"class":105}," \u002F\u002F 创建 Block 根节点\n",[99,1063,1064],{"class":101,"line":166},[99,1065,1066],{"class":105},"\u002F\u002F 内部动态节点都会被收集到 Block 的 dynamicChildren 中\n",[23,1068,1069,1070,1072,1073,40],{},"更新时，运行时只遍历 ",[59,1071,1014],{}," 列表，而不会递归到静态子树。",[27,1074,1075],{},"这使 Diff 复杂度从 O(n³) 降低到与动态节点数量线性相关",[51,1077,1079],{"id":1078},"_3-编译时优化-vs-运行时优化","3. 编译时优化 vs 运行时优化",[789,1081,1082,1095],{},[792,1083,1084],{},[795,1085,1086,1089,1092],{},[798,1087,1088],{},"维度",[798,1090,1091],{},"编译时优化（Vue 3 主导）",[798,1093,1094],{},"运行时优化（Vue 2 为主）",[808,1096,1097,1110,1123,1136,1152],{},[795,1098,1099,1104,1107],{},[813,1100,1101],{},[27,1102,1103],{},"静态提升",[813,1105,1106],{},"✅ 移动到 render 外部",[813,1108,1109],{},"❌ 每次 render 重新创建",[795,1111,1112,1117,1120],{},[813,1113,1114],{},[27,1115,1116],{},"PatchFlag",[813,1118,1119],{},"✅ 编译时收集动态信息",[813,1121,1122],{},"❌ 需要运行时比对",[795,1124,1125,1130,1133],{},[813,1126,1127],{},[27,1128,1129],{},"Block Tree",[813,1131,1132],{},"✅ 收集动态节点路径",[813,1134,1135],{},"❌ 全量递归 Diff",[795,1137,1138,1143,1146],{},[813,1139,1140],{},[27,1141,1142],{},"缓存事件处理器",[813,1144,1145],{},"✅ 自动缓存内联函数",[813,1147,1148,1149],{},"❌ 需手动或借助 ",[59,1150,1151],{},".once",[795,1153,1154,1159,1162],{},[813,1155,1156],{},[27,1157,1158],{},"v-once",[813,1160,1161],{},"编译时标记静态内容",[813,1163,1164],{},"运行时缓存节点",[23,1166,1167,1170,1171,1174],{},[27,1168,1169],{},"结论","：Vue 3 将大量优化工作",[27,1172,1173],{},"前置到编译阶段","，减少了运行时的工作量，从而提升性能。",[51,1176,1178,1179,1182],{"id":1177},"_4-自定义渲染器createrenderer-实现跨平台渲染","4. 自定义渲染器：",[59,1180,1181],{},"createRenderer"," 实现跨平台渲染",[23,1184,1185,1186,1188],{},"Vue 3 将核心渲染逻辑与平台相关操作分离，通过 ",[59,1187,1181],{}," 函数可以构建自定义渲染器，用于非浏览器环境（如小程序、Canvas、WebGL、原生移动端）。",[78,1190,1191],{"id":1191},"核心原理",[23,1193,1194,1197,1198,1201],{},[59,1195,1196],{},"scheduler"," 和渲染器需要实现一套",[27,1199,1200],{},"节点操作 API","（NodeOp），例如：",[374,1203,1204,1209,1214,1219],{},[377,1205,1206],{},[59,1207,1208],{},"createElement(type)",[377,1210,1211],{},[59,1212,1213],{},"insert(child, parent, anchor)",[377,1215,1216],{},[59,1217,1218],{},"setElementText(node, text)",[377,1220,1221],{},[59,1222,1223],{},"patchProp(el, key, prevValue, nextValue)",[90,1225,1227],{"className":92,"code":1226,"language":94,"meta":95,"style":95},"import { createRenderer } from '@vue\u002Fruntime-core';\n\nconst { render, createApp } = createRenderer({\n  \u002F\u002F 平台特定的节点操作\n  createElement(type) { ... },\n  patchProp(el, key, prev, next) { ... },\n  insert(child, parent, anchor) { ... },\n  \u002F\u002F ... 其他必须方法\n});\n\n\u002F\u002F 然后可以用 createApp 创建跨平台应用\nconst app = createApp(RootComponent);\napp.mount(platformContainer);\n",[59,1228,1229,1253,1257,1280,1285,1305,1338,1366,1371,1379,1383,1388,1404],{"__ignoreMap":95},[99,1230,1231,1234,1236,1239,1241,1244,1246,1249,1251],{"class":101,"line":102},[99,1232,1233],{"class":534},"import",[99,1235,251],{"class":112},[99,1237,1238],{"class":141}," createRenderer",[99,1240,265],{"class":112},[99,1242,1243],{"class":534}," from",[99,1245,206],{"class":128},[99,1247,1248],{"class":132},"@vue\u002Fruntime-core",[99,1250,211],{"class":128},[99,1252,612],{"class":112},[99,1254,1255],{"class":101,"line":109},[99,1256,163],{"emptyLinePlaceholder":162},[99,1258,1259,1261,1263,1265,1267,1270,1272,1274,1276,1278],{"class":101,"line":159},[99,1260,694],{"class":507},[99,1262,251],{"class":112},[99,1264,511],{"class":697},[99,1266,192],{"class":112},[99,1268,1269],{"class":697}," createApp",[99,1271,265],{"class":112},[99,1273,701],{"class":124},[99,1275,1238],{"class":510},[99,1277,514],{"class":141},[99,1279,175],{"class":112},[99,1281,1282],{"class":101,"line":166},[99,1283,1284],{"class":105},"  \u002F\u002F 平台特定的节点操作\n",[99,1286,1287,1291,1293,1296,1298,1300,1302],{"class":101,"line":172},[99,1288,1290],{"class":1289},"sVXei","  createElement",[99,1292,514],{"class":112},[99,1294,1295],{"class":517},"type",[99,1297,526],{"class":112},[99,1299,251],{"class":112},[99,1301,1054],{"class":124},[99,1303,1304],{"class":112}," },\n",[99,1306,1307,1310,1312,1315,1317,1320,1322,1325,1327,1330,1332,1334,1336],{"class":101,"line":178},[99,1308,1309],{"class":1289},"  patchProp",[99,1311,514],{"class":112},[99,1313,1314],{"class":517},"el",[99,1316,192],{"class":112},[99,1318,1319],{"class":517}," key",[99,1321,192],{"class":112},[99,1323,1324],{"class":517}," prev",[99,1326,192],{"class":112},[99,1328,1329],{"class":517}," next",[99,1331,526],{"class":112},[99,1333,251],{"class":112},[99,1335,1054],{"class":124},[99,1337,1304],{"class":112},[99,1339,1340,1343,1345,1348,1350,1353,1355,1358,1360,1362,1364],{"class":101,"line":198},[99,1341,1342],{"class":1289},"  insert",[99,1344,514],{"class":112},[99,1346,1347],{"class":517},"child",[99,1349,192],{"class":112},[99,1351,1352],{"class":517}," parent",[99,1354,192],{"class":112},[99,1356,1357],{"class":517}," anchor",[99,1359,526],{"class":112},[99,1361,251],{"class":112},[99,1363,1054],{"class":124},[99,1365,1304],{"class":112},[99,1367,1368],{"class":101,"line":217},[99,1369,1370],{"class":105},"  \u002F\u002F ... 其他必须方法\n",[99,1372,1373,1375,1377],{"class":101,"line":275},[99,1374,952],{"class":112},[99,1376,526],{"class":141},[99,1378,612],{"class":112},[99,1380,1381],{"class":101,"line":286},[99,1382,163],{"emptyLinePlaceholder":162},[99,1384,1385],{"class":101,"line":318},[99,1386,1387],{"class":105},"\u002F\u002F 然后可以用 createApp 创建跨平台应用\n",[99,1389,1390,1392,1395,1397,1399,1402],{"class":101,"line":356},[99,1391,694],{"class":507},[99,1393,1394],{"class":697}," app",[99,1396,701],{"class":124},[99,1398,1269],{"class":510},[99,1400,1401],{"class":141},"(RootComponent)",[99,1403,612],{"class":112},[99,1405,1406,1409,1411,1414,1417],{"class":101,"line":362},[99,1407,1408],{"class":141},"app",[99,1410,599],{"class":112},[99,1412,1413],{"class":510},"mount",[99,1415,1416],{"class":141},"(platformContainer)",[99,1418,612],{"class":112},[23,1420,1421,1424],{},[27,1422,1423],{},"已有实践","：",[374,1426,1427,1433,1439],{},[377,1428,1429,1432],{},[27,1430,1431],{},"Weex","：基于 Vue 2 的跨平台移动端方案，Vue 3 版本使用自定义渲染器。",[377,1434,1435,1438],{},[27,1436,1437],{},"mpvue \u002F uni-app","：将 Vue 组件编译为小程序代码，其核心也是自定义渲染器。",[377,1440,1441,1444],{},[27,1442,1443],{},"vue-threejs","：将 Vue 组件渲染到 Three.js 场景。",[51,1446,1448],{"id":1447},"_5-vnode-的结构与类型","5. VNode 的结构与类型",[23,1450,1451],{},"VNode（虚拟节点）是 Vue 运行时最小的表示单元，类型不同其结构和处理方式也有所差异。",[789,1453,1454,1472],{},[792,1455,1456],{},[795,1457,1458,1461,1466,1469],{},[798,1459,1460],{},"VNode 类型",[798,1462,1463,1465],{},[59,1464,1295],{}," 值",[798,1467,1468],{},"作用",[798,1470,1471],{},"常见场景",[808,1473,1474,1503,1524,1542,1560,1578,1600],{},[795,1475,1476,1481,1491,1494],{},[813,1477,1478],{},[27,1479,1480],{},"元素 VNode",[813,1482,1483,1486,1487,1490],{},[59,1484,1485],{},"string","（如 ",[59,1488,1489],{},"'div'","）",[813,1492,1493],{},"表示真实 DOM 元素",[813,1495,1496,383,1499,1502],{},[59,1497,1498],{},"\u003Cdiv>",[59,1500,1501],{},"\u003Cspan>"," 等",[795,1504,1505,1510,1516,1519],{},[813,1506,1507],{},[27,1508,1509],{},"组件 VNode",[813,1511,1512,1513,1490],{},"组件对象（",[59,1514,1515],{},"Component",[813,1517,1518],{},"表示用户定义的组件",[813,1520,1521],{},[59,1522,1523],{},"\u003CMyComponent>",[795,1525,1526,1531,1536,1539],{},[813,1527,1528],{},[27,1529,1530],{},"文本 VNode",[813,1532,1533],{},[59,1534,1535],{},"Symbol(Text)",[813,1537,1538],{},"纯文本节点",[813,1540,1541],{},"插值、文本内容",[795,1543,1544,1549,1554,1557],{},[813,1545,1546],{},[27,1547,1548],{},"注释 VNode",[813,1550,1551],{},[59,1552,1553],{},"Symbol(Comment)",[813,1555,1556],{},"注释节点",[813,1558,1559],{},"很少直接接触",[795,1561,1562,1567,1572,1575],{},[813,1563,1564],{},[27,1565,1566],{},"静态 VNode",[813,1568,1569,1571],{},[59,1570,1485],{}," + 特殊标记",[813,1573,1574],{},"静态提升节点",[813,1576,1577],{},"被提升的静态元素",[795,1579,1580,1585,1591,1594],{},[813,1581,1582],{},[27,1583,1584],{},"插槽 VNode",[813,1586,1587,1590],{},[59,1588,1589],{},"Symbol(Fragment)"," + 特殊处理",[813,1592,1593],{},"表示插槽内容",[813,1595,1596,1599],{},[59,1597,1598],{},"\u003Cslot>"," 生成",[795,1601,1602,1607,1611,1617],{},[813,1603,1604],{},[27,1605,1606],{},"Fragment",[813,1608,1609],{},[59,1610,1589],{},[813,1612,1613,1614,1616],{},"多根节点或 ",[59,1615,386],{}," 产生的片段",[813,1618,1619],{},"模板片段",[78,1621,1623],{"id":1622},"vnode-核心属性简化","VNode 核心属性（简化）",[90,1625,1627],{"className":92,"code":1626,"language":94,"meta":95,"style":95},"interface VNode {\n  type: any;           \u002F\u002F 元素标签名或组件对象或 Symbol\n  props: any;          \u002F\u002F 属性对象\n  children: any;       \u002F\u002F 子节点（数组或字符串）\n  el: Node | null;     \u002F\u002F 挂载的真实 DOM 节点\n  key: string | number | null;   \u002F\u002F 用于 diff 的 key\n  component: ComponentInternalInstance | null; \u002F\u002F 组件实例（若为组件 VNode）\n  patchFlag: number;   \u002F\u002F 优化标记\n  shapeFlag: number;   \u002F\u002F 节点形状（元素、组件、文本等）\n  \u002F\u002F ...\n}\n",[59,1628,1629,1639,1655,1668,1681,1701,1725,1744,1757,1771,1776],{"__ignoreMap":95},[99,1630,1631,1634,1637],{"class":101,"line":102},[99,1632,1633],{"class":507},"interface",[99,1635,1636],{"class":181}," VNode",[99,1638,529],{"class":112},[99,1640,1641,1644,1646,1650,1652],{"class":101,"line":109},[99,1642,182],{"class":1643},"sucvu",[99,1645,185],{"class":124},[99,1647,1649],{"class":1648},"sZMiF"," any",[99,1651,1034],{"class":112},[99,1653,1654],{"class":105},"           \u002F\u002F 元素标签名或组件对象或 Symbol\n",[99,1656,1657,1659,1661,1663,1665],{"class":101,"line":159},[99,1658,220],{"class":1643},[99,1660,185],{"class":124},[99,1662,1649],{"class":1648},[99,1664,1034],{"class":112},[99,1666,1667],{"class":105},"          \u002F\u002F 属性对象\n",[99,1669,1670,1672,1674,1676,1678],{"class":101,"line":166},[99,1671,278],{"class":1643},[99,1673,185],{"class":124},[99,1675,1649],{"class":1648},[99,1677,1034],{"class":112},[99,1679,1680],{"class":105},"       \u002F\u002F 子节点（数组或字符串）\n",[99,1682,1683,1686,1688,1691,1694,1696,1698],{"class":101,"line":172},[99,1684,1685],{"class":1643},"  el",[99,1687,185],{"class":124},[99,1689,1690],{"class":181}," Node",[99,1692,1693],{"class":124}," |",[99,1695,721],{"class":1648},[99,1697,1034],{"class":112},[99,1699,1700],{"class":105},"     \u002F\u002F 挂载的真实 DOM 节点\n",[99,1702,1703,1706,1708,1711,1713,1716,1718,1720,1722],{"class":101,"line":178},[99,1704,1705],{"class":1643},"  key",[99,1707,185],{"class":124},[99,1709,1710],{"class":1648}," string",[99,1712,1693],{"class":124},[99,1714,1715],{"class":1648}," number",[99,1717,1693],{"class":124},[99,1719,721],{"class":1648},[99,1721,1034],{"class":112},[99,1723,1724],{"class":105},"   \u002F\u002F 用于 diff 的 key\n",[99,1726,1727,1730,1732,1735,1737,1739,1741],{"class":101,"line":198},[99,1728,1729],{"class":1643},"  component",[99,1731,185],{"class":124},[99,1733,1734],{"class":181}," ComponentInternalInstance",[99,1736,1693],{"class":124},[99,1738,721],{"class":1648},[99,1740,1034],{"class":112},[99,1742,1743],{"class":105}," \u002F\u002F 组件实例（若为组件 VNode）\n",[99,1745,1746,1748,1750,1752,1754],{"class":101,"line":217},[99,1747,432],{"class":1643},[99,1749,185],{"class":124},[99,1751,1715],{"class":1648},[99,1753,1034],{"class":112},[99,1755,1756],{"class":105},"   \u002F\u002F 优化标记\n",[99,1758,1759,1762,1764,1766,1768],{"class":101,"line":275},[99,1760,1761],{"class":1643},"  shapeFlag",[99,1763,185],{"class":124},[99,1765,1715],{"class":1648},[99,1767,1034],{"class":112},[99,1769,1770],{"class":105},"   \u002F\u002F 节点形状（元素、组件、文本等）\n",[99,1772,1773],{"class":101,"line":286},[99,1774,1775],{"class":105},"  \u002F\u002F ...\n",[99,1777,1778],{"class":101,"line":318},[99,1779,365],{"class":112},[23,1781,1782,1785,1786,1788,1789,1792,1793,383,1796,383,1799,1802],{},[27,1783,1784],{},"为什么 VNode 需要 shapeFlag","：因为 ",[59,1787,1295],{}," 可能是字符串或对象，运行时需要快速知道节点类型以选择处理逻辑。",[59,1790,1791],{},"shapeFlag"," 使用位掩码高效组合多种特征（如 ",[59,1794,1795],{},"STATEFUL_COMPONENT",[59,1797,1798],{},"SUSPENSE",[59,1800,1801],{},"TELEPORT","）。",[51,1804,1805],{"id":1805},"总结",[789,1807,1808,1818],{},[792,1809,1810],{},[795,1811,1812,1815],{},[798,1813,1814],{},"主题",[798,1816,1817],{},"关键点",[808,1819,1820,1830,1840,1850,1863],{},[795,1821,1822,1827],{},[813,1823,1824],{},[27,1825,1826],{},"模板编译",[813,1828,1829],{},"解析 → 转换 → 生成 render；产出带有优化标记的代码",[795,1831,1832,1837],{},[813,1833,1834],{},[27,1835,1836],{},"Diff 优化",[813,1838,1839],{},"静态提升（复用 VNode）、PatchFlag（精准更新）、Block Tree（扁平动态节点）",[795,1841,1842,1847],{},[813,1843,1844],{},[27,1845,1846],{},"编译时 vs 运行时",[813,1848,1849],{},"Vue 3 强调编译时标记，减少运行时比对，性能优于 Vue 2",[795,1851,1852,1857],{},[813,1853,1854],{},[27,1855,1856],{},"自定义渲染器",[813,1858,1859,1860,1862],{},"通过 ",[59,1861,1181],{}," 实现跨平台，需要平台特定的节点操作 API",[795,1864,1865,1869],{},[813,1866,1867],{},[27,1868,1460],{},[813,1870,1871,1872,1874],{},"元素、组件、文本、Fragment、插槽等；通过 ",[59,1873,1791],{}," 快速区分并处理",[23,1876,1877],{},"理解这些底层机制，不仅能写出更优雅的代码（例如利用静态提升避免不必要的计算），也能在需要深度定制渲染行为时游刃有余。",[1879,1880,1881],"h2",{"id":1881},"参考文献",[23,1883,1884],{},"以下链接在编写时均可正常访问：",[789,1886,1887,1897],{},[792,1888,1889],{},[795,1890,1891,1894],{},[798,1892,1893],{},"资料",[798,1895,1896],{},"说明",[808,1898,1899,1912,1924],{},[795,1900,1901,1909],{},[813,1902,1903],{},[36,1904,1908],{"href":1905,"rel":1906},"https:\u002F\u002Fcn.vuejs.org\u002Fguide\u002Fextras\u002Frendering-mechanism.html",[1907],"nofollow","Vue：渲染机制",[813,1910,1911],{},"官方深度说明",[795,1913,1914,1921],{},[813,1915,1916],{},[36,1917,1920],{"href":1918,"rel":1919},"https:\u002F\u002Fcn.vuejs.org\u002Fguide\u002Fextras\u002Frender-function.html",[1907],"Vue：渲染函数",[813,1922,1923],{},"render \u002F h",[795,1925,1926,1932],{},[813,1927,1928],{},[36,1929,76],{"href":1930,"rel":1931},"https:\u002F\u002Fgithub.com\u002Fvuejs\u002Fcore\u002Ftree\u002Fmain\u002Fpackages\u002Fcompiler-core",[1907],[813,1933,1934],{},"编译器源码（英文）",[1936,1937,1938],"style",{},"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 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 .smGrS, html code.shiki .smGrS{--shiki-light:#39ADB5;--shiki-default:#D73A49;--shiki-dark:#F97583}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 .su5hD, html code.shiki .su5hD{--shiki-light:#90A4AE;--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sbgvK, html code.shiki .sbgvK{--shiki-light:#E2931D;--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .srdBf, html code.shiki .srdBf{--shiki-light:#F76D47;--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .skxfh, html code.shiki .skxfh{--shiki-light:#E53935;--shiki-default:#24292E;--shiki-dark:#E1E4E8}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 .sbsja, html code.shiki .sbsja{--shiki-light:#9C3EDA;--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sGLFI, html code.shiki .sGLFI{--shiki-light:#6182B8;--shiki-default:#6F42C1;--shiki-dark:#B392F0}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 .s_hVV, html code.shiki .s_hVV{--shiki-light:#90A4AE;--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .s39Yj, html code.shiki .s39Yj{--shiki-light:#39ADB5;--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sVXei, html code.shiki .sVXei{--shiki-light:#E53935;--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sucvu, html code.shiki .sucvu{--shiki-light:#E53935;--shiki-default:#E36209;--shiki-dark:#FFAB70}html pre.shiki code .sZMiF, html code.shiki .sZMiF{--shiki-light:#E2931D;--shiki-default:#005CC5;--shiki-dark:#79B8FF}",{"title":95,"searchDepth":109,"depth":109,"links":1940},[1941,1942,1943,1944,1946,1947,1948],{"id":53,"depth":159,"text":54},{"id":632,"depth":159,"text":633},{"id":1078,"depth":159,"text":1079},{"id":1177,"depth":159,"text":1945},"4. 自定义渲染器：createRenderer 实现跨平台渲染",{"id":1447,"depth":159,"text":1448},{"id":1805,"depth":159,"text":1805},{"id":1881,"depth":109,"text":1881},{"title":8,"description":9},"knowledge\u002Fbooklet\u002Fframe\u002FVue\u002Frender","knowledge\u002Fknowledge\u002Fbooklet\u002Fframe\u002FVue\u002Frender.md","md",{"items":1954},[1955,1959,1963,1967,1971,1975],{"path":1956,"title":1957,"description":1958,"category":10,"score":178},"\u002Fknowledge\u002Fbooklet\u002Fframe\u002Fvue\u002Fperformance\u002Fassets","资源优化","图片懒加载、按需引入与 Web Vitals 监控。见 HTML 图片、CSS 字体优化。",{"path":1960,"title":1961,"description":1962,"category":10,"score":178},"\u002Fknowledge\u002Fbooklet\u002Fframe\u002Fvue\u002Fstatus","状态管理：Pinia 与 Vuex","Pinia 是 Vue 官方推荐的状态管理库（Vue 3 新项目默认选型）。Vuex 4 仍可与 Vue 3 配合，用于维护旧项目。见 Vue 基础。",{"path":1964,"title":1965,"description":1966,"category":10,"score":178},"\u002Fknowledge\u002Fbooklet\u002Fframe\u002Fvue\u002Fecology","Vue 生态关键库深度集成","VueUse、Vite 与 Nuxt 是 Vue 3 生态中常用的效率与工程化方案。概览见 Vue 基础。",{"path":1968,"title":1969,"description":1970,"category":10,"score":178},"\u002Fknowledge\u002Fbooklet\u002Fframe\u002Fvue\u002Freactivity\u002Ftrack","依赖收集与派发更新机制","说明 Vue 3 中 track \u002F trigger 与 targetMap 的工作方式。前置：v2-v3 差异。",{"path":1972,"title":1973,"description":1974,"category":10,"score":178},"\u002Fknowledge\u002Fbooklet\u002Fframe\u002Fvue\u002Ftest","测试策略","Vue 应用常用 Vitest + @vue\u002Ftest-utils 做单元\u002F组件测试，Playwright 或 Cypress 做 E2E。见 Vue 基础。",{"path":1976,"title":1977,"description":1978,"category":10,"score":178},"\u002Fknowledge\u002Fbooklet\u002Fframe\u002Fvue\u002Fdesign","组合式 API 与逻辑复用设计模式","组合式 API 与 Composables 是 Vue 3 推荐的逻辑组织方式。概览见 Vue 基础。",{"series":1980,"title":12,"items":1981,"index":217,"prev":2029,"next":2030},"booklet\u002Fframe\u002Fvue",[1982,1984,1986,1990,1992,1994,1998,2002,2006,2007,2011,2015,2017,2019,2021,2025],{"path":1956,"title":1957,"date":1983,"pinned":15},"2025-11-06",{"path":38,"title":39,"date":1985,"pinned":15},"2021-07-29",{"path":1987,"title":1988,"date":1989,"pinned":15},"\u002Fknowledge\u002Fbooklet\u002Fframe\u002Fvue\u002Fperformance\u002Fbuild","编译与打包优化","2021-08-02",{"path":1976,"title":1977,"date":1991,"pinned":15},"2024-06-16",{"path":1964,"title":1965,"date":1993,"pinned":15},"2025-08-26",{"path":1995,"title":1996,"date":1997,"pinned":15},"\u002Fknowledge\u002Fbooklet\u002Fframe\u002Fvue\u002Fproject","工程化实践","2021-07-20",{"path":1999,"title":2000,"date":2001,"pinned":15},"\u002Fknowledge\u002Fbooklet\u002Fframe\u002Fvue\u002Fprops","组件通信与跨层级设计模式","2023-03-23",{"path":2003,"title":2004,"date":2005,"pinned":15},"\u002Fknowledge\u002Fbooklet\u002Fframe\u002Fvue\u002Freactivity\u002Fproxy","响应式进阶","2023-03-21",{"path":7,"title":8,"date":14,"pinned":15},{"path":2008,"title":2009,"date":2010,"pinned":15},"\u002Fknowledge\u002Fbooklet\u002Fframe\u002Fvue\u002Frouter","路由与权限控制","2021-09-12",{"path":2012,"title":2013,"date":2014,"pinned":15},"\u002Fknowledge\u002Fbooklet\u002Fframe\u002Fvue\u002Fperformance\u002Fruntime","运行时优化","2021-06-10",{"path":1960,"title":1961,"date":2016,"pinned":15},"2025-10-11",{"path":1972,"title":1973,"date":2018,"pinned":15},"2024-10-23",{"path":1968,"title":1969,"date":2020,"pinned":15},"2025-01-13",{"path":2022,"title":2023,"date":2024,"pinned":15},"\u002Fknowledge\u002Fbooklet\u002Fframe\u002Fvue\u002Ftypescript","TypeScript 深度集成","2023-11-29",{"path":2026,"title":2027,"date":2028,"pinned":15},"\u002Fknowledge\u002Fbooklet\u002Fframe\u002Fvue\u002Freactivity\u002Fv2-v3","Vue 2 与 Vue 3 响应式差异","2022-07-06",{"path":2003,"title":2004,"date":2005,"pinned":15},{"path":2008,"title":2009,"date":2010,"pinned":15}]