[{"data":1,"prerenderedAt":1373},["ShallowReactive",2],{"page-\u002Fvue\u002Fruntime-dom":3},{"id":4,"title":5,"body":6,"description":1366,"extension":1367,"meta":1368,"navigation":426,"path":1369,"seo":1370,"stem":1371,"__hash__":1372},"content\u002FVue\u002Fruntime-dom.md","Runtime Dom",{"type":7,"value":8,"toc":1360},"minimark",[9,22,25,29,32,285,288,345,348,506,508,511,703,706,709,712,715,718,750,754,761,882,912,974,1064,1067,1284,1287,1290,1297,1356],[10,11,12,16,17,21],"p",{},[13,14,15],"code",{},"runtime-dom"," 是 Vue 3 源码中的一个核心包，它提供了",[18,19,20],"strong",{},"与浏览器 DOM 相关的运行时功能","。",[10,23,24],{},"除此以外，还包含了reactivity响应式系统、runtime-core 运行时核心（这个包含了组件、渲染器、虚拟DOM），我们的runtime-dom包含浏览器DOM的特定实现，比如DOM操作、事件和属性，complier-dom：浏览器模板编译器。",[26,27,28],"h2",{"id":28},"职责",[10,30,31],{},"通过runtime-dom我们可以创还能针对浏览器DOM的渲染器",[33,34,39],"pre",{"className":35,"code":36,"language":37,"meta":38,"style":38},"language-js shiki shiki-themes github-light github-dark","\u002F\u002F runtime-dom 创建针对浏览器 DOM 的渲染器\nconst renderer = createRenderer({\n  \u002F\u002F 平台特定的节点操作\n  createElement(type) {\n    return document.createElement(type)\n  },\n  setElementText(node, text) {\n    node.textContent = text\n  },\n  patchProp(el, key, prevValue, nextValue) {\n    \u002F\u002F 处理属性、事件、样式等\n    if (key === 'class') { ... }\n    else if (key === 'style') { ... }\n    else if (isOn(key)) { ... } \u002F\u002F 事件 @click\n    else { ... }\n  },\n  \u002F\u002F ... 其他 DOM 操作\n})\n","js","",[13,40,41,50,72,78,94,109,115,134,146,151,179,185,210,232,256,268,273,279],{"__ignoreMap":38},[42,43,46],"span",{"class":44,"line":45},"line",1,[42,47,49],{"class":48},"sJ8bj","\u002F\u002F runtime-dom 创建针对浏览器 DOM 的渲染器\n",[42,51,53,57,61,64,68],{"class":44,"line":52},2,[42,54,56],{"class":55},"szBVR","const",[42,58,60],{"class":59},"sj4cs"," renderer",[42,62,63],{"class":55}," =",[42,65,67],{"class":66},"sScJk"," createRenderer",[42,69,71],{"class":70},"sVt8B","({\n",[42,73,75],{"class":44,"line":74},3,[42,76,77],{"class":48},"  \u002F\u002F 平台特定的节点操作\n",[42,79,81,84,87,91],{"class":44,"line":80},4,[42,82,83],{"class":66},"  createElement",[42,85,86],{"class":70},"(",[42,88,90],{"class":89},"s4XuR","type",[42,92,93],{"class":70},") {\n",[42,95,97,100,103,106],{"class":44,"line":96},5,[42,98,99],{"class":55},"    return",[42,101,102],{"class":70}," document.",[42,104,105],{"class":66},"createElement",[42,107,108],{"class":70},"(type)\n",[42,110,112],{"class":44,"line":111},6,[42,113,114],{"class":70},"  },\n",[42,116,118,121,123,126,129,132],{"class":44,"line":117},7,[42,119,120],{"class":66},"  setElementText",[42,122,86],{"class":70},[42,124,125],{"class":89},"node",[42,127,128],{"class":70},", ",[42,130,131],{"class":89},"text",[42,133,93],{"class":70},[42,135,137,140,143],{"class":44,"line":136},8,[42,138,139],{"class":70},"    node.textContent ",[42,141,142],{"class":55},"=",[42,144,145],{"class":70}," text\n",[42,147,149],{"class":44,"line":148},9,[42,150,114],{"class":70},[42,152,154,157,159,162,164,167,169,172,174,177],{"class":44,"line":153},10,[42,155,156],{"class":66},"  patchProp",[42,158,86],{"class":70},[42,160,161],{"class":89},"el",[42,163,128],{"class":70},[42,165,166],{"class":89},"key",[42,168,128],{"class":70},[42,170,171],{"class":89},"prevValue",[42,173,128],{"class":70},[42,175,176],{"class":89},"nextValue",[42,178,93],{"class":70},[42,180,182],{"class":44,"line":181},11,[42,183,184],{"class":48},"    \u002F\u002F 处理属性、事件、样式等\n",[42,186,188,191,194,197,201,204,207],{"class":44,"line":187},12,[42,189,190],{"class":55},"    if",[42,192,193],{"class":70}," (key ",[42,195,196],{"class":55},"===",[42,198,200],{"class":199},"sZZnC"," 'class'",[42,202,203],{"class":70},") { ",[42,205,206],{"class":55},"...",[42,208,209],{"class":70}," }\n",[42,211,213,216,219,221,223,226,228,230],{"class":44,"line":212},13,[42,214,215],{"class":55},"    else",[42,217,218],{"class":55}," if",[42,220,193],{"class":70},[42,222,196],{"class":55},[42,224,225],{"class":199}," 'style'",[42,227,203],{"class":70},[42,229,206],{"class":55},[42,231,209],{"class":70},[42,233,235,237,239,242,245,248,250,253],{"class":44,"line":234},14,[42,236,215],{"class":55},[42,238,218],{"class":55},[42,240,241],{"class":70}," (",[42,243,244],{"class":66},"isOn",[42,246,247],{"class":70},"(key)) { ",[42,249,206],{"class":55},[42,251,252],{"class":70}," } ",[42,254,255],{"class":48},"\u002F\u002F 事件 @click\n",[42,257,259,261,264,266],{"class":44,"line":258},15,[42,260,215],{"class":55},[42,262,263],{"class":70}," { ",[42,265,206],{"class":55},[42,267,209],{"class":70},[42,269,271],{"class":44,"line":270},16,[42,272,114],{"class":70},[42,274,276],{"class":44,"line":275},17,[42,277,278],{"class":48},"  \u002F\u002F ... 其他 DOM 操作\n",[42,280,282],{"class":44,"line":281},18,[42,283,284],{"class":70},"})\n",[10,286,287],{},"它还负责导出浏览器专用的API：",[33,289,291],{"className":35,"code":290,"language":37,"meta":38,"style":38},"\u002F\u002F 从 runtime-dom 导出的核心 API\nexport {\n  createApp,        \u002F\u002F 创建 Vue 应用\n  render,           \u002F\u002F 渲染函数\n  h,                \u002F\u002F 创建 VNode\n  createElementVNode,\n  \u002F\u002F ... 其他\n}\n",[13,292,293,298,306,314,322,330,335,340],{"__ignoreMap":38},[42,294,295],{"class":44,"line":45},[42,296,297],{"class":48},"\u002F\u002F 从 runtime-dom 导出的核心 API\n",[42,299,300,303],{"class":44,"line":52},[42,301,302],{"class":55},"export",[42,304,305],{"class":70}," {\n",[42,307,308,311],{"class":44,"line":74},[42,309,310],{"class":70},"  createApp,        ",[42,312,313],{"class":48},"\u002F\u002F 创建 Vue 应用\n",[42,315,316,319],{"class":44,"line":80},[42,317,318],{"class":70},"  render,           ",[42,320,321],{"class":48},"\u002F\u002F 渲染函数\n",[42,323,324,327],{"class":44,"line":96},[42,325,326],{"class":70},"  h,                ",[42,328,329],{"class":48},"\u002F\u002F 创建 VNode\n",[42,331,332],{"class":44,"line":111},[42,333,334],{"class":70},"  createElementVNode,\n",[42,336,337],{"class":44,"line":117},[42,338,339],{"class":48},"  \u002F\u002F ... 其他\n",[42,341,342],{"class":44,"line":136},[42,343,344],{"class":70},"}\n",[10,346,347],{},"可以看出runtime-dom的职责就是DOM实现，是平台相关内容，就是负责补充DOM操作细节的。runtime-core的职责是浏览器的核心逻辑，是平台无关的，它负责虚拟DOM、组件系统。",[33,349,351],{"className":35,"code":350,"language":37,"meta":38,"style":38},"\u002F\u002F runtime-core 中的渲染器基类\nfunction createRenderer(nodeOps) {\n  \u002F\u002F 通用渲染逻辑\n  function render(vnode, container) {\n    \u002F\u002F 调用 nodeOps 的方法操作平台特定节点\n    nodeOps.insert(el, container)\n  }\n}\n\n\u002F\u002F runtime-dom 注入 DOM 操作实现\nconst renderer = createRenderer({\n  insert: (el, parent) => parent.appendChild(el),\n  remove: el => el.remove(),\n  \u002F\u002F ...\n})\n",[13,352,353,358,372,377,397,402,413,418,422,428,433,445,475,497,502],{"__ignoreMap":38},[42,354,355],{"class":44,"line":45},[42,356,357],{"class":48},"\u002F\u002F runtime-core 中的渲染器基类\n",[42,359,360,363,365,367,370],{"class":44,"line":52},[42,361,362],{"class":55},"function",[42,364,67],{"class":66},[42,366,86],{"class":70},[42,368,369],{"class":89},"nodeOps",[42,371,93],{"class":70},[42,373,374],{"class":44,"line":74},[42,375,376],{"class":48},"  \u002F\u002F 通用渲染逻辑\n",[42,378,379,382,385,387,390,392,395],{"class":44,"line":80},[42,380,381],{"class":55},"  function",[42,383,384],{"class":66}," render",[42,386,86],{"class":70},[42,388,389],{"class":89},"vnode",[42,391,128],{"class":70},[42,393,394],{"class":89},"container",[42,396,93],{"class":70},[42,398,399],{"class":44,"line":96},[42,400,401],{"class":48},"    \u002F\u002F 调用 nodeOps 的方法操作平台特定节点\n",[42,403,404,407,410],{"class":44,"line":111},[42,405,406],{"class":70},"    nodeOps.",[42,408,409],{"class":66},"insert",[42,411,412],{"class":70},"(el, container)\n",[42,414,415],{"class":44,"line":117},[42,416,417],{"class":70},"  }\n",[42,419,420],{"class":44,"line":136},[42,421,344],{"class":70},[42,423,424],{"class":44,"line":148},[42,425,427],{"emptyLinePlaceholder":426},true,"\n",[42,429,430],{"class":44,"line":153},[42,431,432],{"class":48},"\u002F\u002F runtime-dom 注入 DOM 操作实现\n",[42,434,435,437,439,441,443],{"class":44,"line":181},[42,436,56],{"class":55},[42,438,60],{"class":59},[42,440,63],{"class":55},[42,442,67],{"class":66},[42,444,71],{"class":70},[42,446,447,450,453,455,457,460,463,466,469,472],{"class":44,"line":187},[42,448,449],{"class":66},"  insert",[42,451,452],{"class":70},": (",[42,454,161],{"class":89},[42,456,128],{"class":70},[42,458,459],{"class":89},"parent",[42,461,462],{"class":70},") ",[42,464,465],{"class":55},"=>",[42,467,468],{"class":70}," parent.",[42,470,471],{"class":66},"appendChild",[42,473,474],{"class":70},"(el),\n",[42,476,477,480,483,485,488,491,494],{"class":44,"line":212},[42,478,479],{"class":66},"  remove",[42,481,482],{"class":70},": ",[42,484,161],{"class":89},[42,486,487],{"class":55}," =>",[42,489,490],{"class":70}," el.",[42,492,493],{"class":66},"remove",[42,495,496],{"class":70},"(),\n",[42,498,499],{"class":44,"line":234},[42,500,501],{"class":48},"  \u002F\u002F ...\n",[42,503,504],{"class":44,"line":258},[42,505,284],{"class":70},[26,507,389],{"id":389},[10,509,510],{},"我们熟悉的VNode实现在runtime-core中的，虚拟DOM属于平台无关的核心概念：",[33,512,516],{"className":513,"code":514,"language":515,"meta":38,"style":38},"language-ts shiki shiki-themes github-light github-dark","\u002F\u002F packages\u002Fruntime-core\u002Fsrc\u002Fvnode.ts\nexport interface VNode\u003CHostNode = any, HostElement = any> {\n  type: any\n  props: any\n  key: string | number | symbol | null\n  ref: any\n  children: any\n  component: ComponentInternalInstance | null\n  el: HostNode | null\n  \u002F\u002F ... 其他属性\n}\n\nexport function createVNode(type, props, children): VNode {\n  \u002F\u002F 创建 VNode 的逻辑\n}\n","ts",[13,517,518,523,556,567,576,602,611,620,634,648,653,657,661,694,699],{"__ignoreMap":38},[42,519,520],{"class":44,"line":45},[42,521,522],{"class":48},"\u002F\u002F packages\u002Fruntime-core\u002Fsrc\u002Fvnode.ts\n",[42,524,525,527,530,533,536,539,541,544,546,549,551,553],{"class":44,"line":52},[42,526,302],{"class":55},[42,528,529],{"class":55}," interface",[42,531,532],{"class":66}," VNode",[42,534,535],{"class":70},"\u003C",[42,537,538],{"class":66},"HostNode",[42,540,63],{"class":55},[42,542,543],{"class":59}," any",[42,545,128],{"class":70},[42,547,548],{"class":66},"HostElement",[42,550,63],{"class":55},[42,552,543],{"class":59},[42,554,555],{"class":70},"> {\n",[42,557,558,561,564],{"class":44,"line":74},[42,559,560],{"class":89},"  type",[42,562,563],{"class":55},":",[42,565,566],{"class":59}," any\n",[42,568,569,572,574],{"class":44,"line":80},[42,570,571],{"class":89},"  props",[42,573,563],{"class":55},[42,575,566],{"class":59},[42,577,578,581,583,586,589,592,594,597,599],{"class":44,"line":96},[42,579,580],{"class":89},"  key",[42,582,563],{"class":55},[42,584,585],{"class":59}," string",[42,587,588],{"class":55}," |",[42,590,591],{"class":59}," number",[42,593,588],{"class":55},[42,595,596],{"class":59}," symbol",[42,598,588],{"class":55},[42,600,601],{"class":59}," null\n",[42,603,604,607,609],{"class":44,"line":111},[42,605,606],{"class":89},"  ref",[42,608,563],{"class":55},[42,610,566],{"class":59},[42,612,613,616,618],{"class":44,"line":117},[42,614,615],{"class":89},"  children",[42,617,563],{"class":55},[42,619,566],{"class":59},[42,621,622,625,627,630,632],{"class":44,"line":136},[42,623,624],{"class":89},"  component",[42,626,563],{"class":55},[42,628,629],{"class":66}," ComponentInternalInstance",[42,631,588],{"class":55},[42,633,601],{"class":59},[42,635,636,639,641,644,646],{"class":44,"line":148},[42,637,638],{"class":89},"  el",[42,640,563],{"class":55},[42,642,643],{"class":66}," HostNode",[42,645,588],{"class":55},[42,647,601],{"class":59},[42,649,650],{"class":44,"line":153},[42,651,652],{"class":48},"  \u002F\u002F ... 其他属性\n",[42,654,655],{"class":44,"line":181},[42,656,344],{"class":70},[42,658,659],{"class":44,"line":187},[42,660,427],{"emptyLinePlaceholder":426},[42,662,663,665,668,671,673,675,677,680,682,685,688,690,692],{"class":44,"line":212},[42,664,302],{"class":55},[42,666,667],{"class":55}," function",[42,669,670],{"class":66}," createVNode",[42,672,86],{"class":70},[42,674,90],{"class":89},[42,676,128],{"class":70},[42,678,679],{"class":89},"props",[42,681,128],{"class":70},[42,683,684],{"class":89},"children",[42,686,687],{"class":70},")",[42,689,563],{"class":55},[42,691,532],{"class":66},[42,693,305],{"class":70},[42,695,696],{"class":44,"line":234},[42,697,698],{"class":48},"  \u002F\u002F 创建 VNode 的逻辑\n",[42,700,701],{"class":44,"line":258},[42,702,344],{"class":70},[10,704,705],{},"正因为如此，我们完全就可以在服务端使用VNode来生成HTML字符串，或者是小程序使用。",[10,707,708],{},"虚拟DOM就是为了在频繁的UI更新中，用js的计算成本来换取昂贵的DOM操作成本，因为真实的DOM操作涉及到了创建元素，修改属性、插入节点、删除等操作，开销都比较大，容易出发样式的重新计算、布局，DOM树重构，而且DOM对象本身也比较重，有大量属性和方法。",[10,710,711],{},"通过虚拟DOM我们就可以用js对象来描述真实DOM结构，这样玩法就比较大了，我们可以进行批量更新，将多次修改合成一次DOM操作，可以做到跨平台渲染，能够制作声明式UI描述UI长相，只更新变化部分，避免全量更新。",[10,713,714],{},"虚拟DOM操作是逃不开合并批量更新和diff算法自动处理的。diff和列表顺序变化是一起的，如果没有key，diff算法效率就会极低，甚至产生错误更新。",[10,716,717],{},"我们熟悉的v-for也是列表实现的，通过列表，可以数据驱动，自动更新，让diff算法自动处理，模板能够统一和保持一致。",[33,719,723],{"className":720,"code":721,"language":722,"meta":38,"style":38},"language-mermaid shiki shiki-themes github-light github-dark","flowchart LR\n    A[数据列表\u003Cbr\u002F>Array] -->|v-for| B[遍历]\n    B --> C[生成 VNode 列表]\n    C --> D[diff 算法]\n    D --> E[最小化 DOM 更新]\n","mermaid",[13,724,725,730,735,740,745],{"__ignoreMap":38},[42,726,727],{"class":44,"line":45},[42,728,729],{},"flowchart LR\n",[42,731,732],{"class":44,"line":52},[42,733,734],{},"    A[数据列表\u003Cbr\u002F>Array] -->|v-for| B[遍历]\n",[42,736,737],{"class":44,"line":74},[42,738,739],{},"    B --> C[生成 VNode 列表]\n",[42,741,742],{"class":44,"line":80},[42,743,744],{},"    C --> D[diff 算法]\n",[42,746,747],{"class":44,"line":96},[42,748,749],{},"    D --> E[最小化 DOM 更新]\n",[751,752,753],"h3",{"id":753},"组件工厂",[10,755,756,757,760],{},"VNode 和组件工厂（Component Factory）是",[18,758,759],{},"强耦合","的，我们可以根据组件工厂来生产VNode。",[33,762,764],{"className":35,"code":763,"language":37,"meta":38,"style":38},"\u002F\u002F 组件定义\nconst MyComponent = {\n  setup() {\n    return () => h('div', 'Hello')\n  }\n}\n\n\u002F\u002F 创建 VNode 时，type 是组件对象\nconst vnode = h(MyComponent)\n\u002F\u002F vnode = {\n\u002F\u002F   type: MyComponent,  \u002F\u002F ← 组件定义\n\u002F\u002F   props: {},\n\u002F\u002F   children: null,\n\u002F\u002F   component: null     \u002F\u002F 渲染时会创建组件实例\n\u002F\u002F }\n",[13,765,766,771,782,790,815,819,823,827,832,846,851,859,864,869,877],{"__ignoreMap":38},[42,767,768],{"class":44,"line":45},[42,769,770],{"class":48},"\u002F\u002F 组件定义\n",[42,772,773,775,778,780],{"class":44,"line":52},[42,774,56],{"class":55},[42,776,777],{"class":59}," MyComponent",[42,779,63],{"class":55},[42,781,305],{"class":70},[42,783,784,787],{"class":44,"line":74},[42,785,786],{"class":66},"  setup",[42,788,789],{"class":70},"() {\n",[42,791,792,794,797,799,802,804,807,809,812],{"class":44,"line":80},[42,793,99],{"class":55},[42,795,796],{"class":70}," () ",[42,798,465],{"class":55},[42,800,801],{"class":66}," h",[42,803,86],{"class":70},[42,805,806],{"class":199},"'div'",[42,808,128],{"class":70},[42,810,811],{"class":199},"'Hello'",[42,813,814],{"class":70},")\n",[42,816,817],{"class":44,"line":96},[42,818,417],{"class":70},[42,820,821],{"class":44,"line":111},[42,822,344],{"class":70},[42,824,825],{"class":44,"line":117},[42,826,427],{"emptyLinePlaceholder":426},[42,828,829],{"class":44,"line":136},[42,830,831],{"class":48},"\u002F\u002F 创建 VNode 时，type 是组件对象\n",[42,833,834,836,839,841,843],{"class":44,"line":148},[42,835,56],{"class":55},[42,837,838],{"class":59}," vnode",[42,840,63],{"class":55},[42,842,801],{"class":66},[42,844,845],{"class":70},"(MyComponent)\n",[42,847,848],{"class":44,"line":153},[42,849,850],{"class":48},"\u002F\u002F vnode = {\n",[42,852,853,856],{"class":44,"line":181},[42,854,855],{"class":48},"\u002F\u002F   type: MyComponent,",[42,857,858],{"class":48},"  \u002F\u002F ← 组件定义\n",[42,860,861],{"class":44,"line":187},[42,862,863],{"class":48},"\u002F\u002F   props: {},\n",[42,865,866],{"class":44,"line":212},[42,867,868],{"class":48},"\u002F\u002F   children: null,\n",[42,870,871,874],{"class":44,"line":234},[42,872,873],{"class":48},"\u002F\u002F   component: null",[42,875,876],{"class":48},"     \u002F\u002F 渲染时会创建组件实例\n",[42,878,879],{"class":44,"line":258},[42,880,881],{"class":48},"\u002F\u002F }\n",[10,883,884,885,888,889,892,893,896,897,899,900,903,904,907,908,911],{},"h()是vue的虚拟DOM创建方法，全称叫做createVNode，",[13,886,887],{},"h"," 是它的简写。\n",[13,890,891],{},"h()"," 接收类型、属性、子节点三个参数，返回一个描述 UI 结构的 ",[18,894,895],{},"JavaScript 对象","（VNode）。",[13,898,887],{}," 是 ",[18,901,902],{},"hyperscript"," 的缩写，意为“",[18,905,906],{},"描述 HTML 结构的 JavaScript 脚本","”，这个概念最早源于 React 的 ",[13,909,910],{},"React.createElement","，Vue 沿用了这个命名",[33,913,915],{"className":35,"code":914,"language":37,"meta":38,"style":38},"\u002F\u002F React 写法\nReact.createElement('div', { className: 'container' }, 'Hello')\n\n\u002F\u002F Vue 写法（更简洁）\nh('div', { class: 'container' }, 'Hello')\n",[13,916,917,922,946,950,955],{"__ignoreMap":38},[42,918,919],{"class":44,"line":45},[42,920,921],{"class":48},"\u002F\u002F React 写法\n",[42,923,924,927,929,931,933,936,939,942,944],{"class":44,"line":52},[42,925,926],{"class":70},"React.",[42,928,105],{"class":66},[42,930,86],{"class":70},[42,932,806],{"class":199},[42,934,935],{"class":70},", { className: ",[42,937,938],{"class":199},"'container'",[42,940,941],{"class":70}," }, ",[42,943,811],{"class":199},[42,945,814],{"class":70},[42,947,948],{"class":44,"line":74},[42,949,427],{"emptyLinePlaceholder":426},[42,951,952],{"class":44,"line":80},[42,953,954],{"class":48},"\u002F\u002F Vue 写法（更简洁）\n",[42,956,957,959,961,963,966,968,970,972],{"class":44,"line":96},[42,958,887],{"class":66},[42,960,86],{"class":70},[42,962,806],{"class":199},[42,964,965],{"class":70},", { class: ",[42,967,938],{"class":199},[42,969,941],{"class":70},[42,971,811],{"class":199},[42,973,814],{"class":70},[33,975,977],{"className":35,"code":976,"language":37,"meta":38,"style":38},"\u002F\u002F 创建单个元素\nh('div', { class: 'container' }, 'Hello Vue')\n\n\u002F\u002F 返回的 VNode 对象（简化）\n{\n  type: 'div',\n  props: { class: 'container' },\n  children: 'Hello Vue',\n  \u002F\u002F ... 其他内部属性\n}\n",[13,978,979,984,1003,1007,1012,1017,1028,1045,1055,1060],{"__ignoreMap":38},[42,980,981],{"class":44,"line":45},[42,982,983],{"class":48},"\u002F\u002F 创建单个元素\n",[42,985,986,988,990,992,994,996,998,1001],{"class":44,"line":52},[42,987,887],{"class":66},[42,989,86],{"class":70},[42,991,806],{"class":199},[42,993,965],{"class":70},[42,995,938],{"class":199},[42,997,941],{"class":70},[42,999,1000],{"class":199},"'Hello Vue'",[42,1002,814],{"class":70},[42,1004,1005],{"class":44,"line":74},[42,1006,427],{"emptyLinePlaceholder":426},[42,1008,1009],{"class":44,"line":80},[42,1010,1011],{"class":48},"\u002F\u002F 返回的 VNode 对象（简化）\n",[42,1013,1014],{"class":44,"line":96},[42,1015,1016],{"class":70},"{\n",[42,1018,1019,1021,1023,1025],{"class":44,"line":111},[42,1020,560],{"class":66},[42,1022,482],{"class":70},[42,1024,806],{"class":199},[42,1026,1027],{"class":70},",\n",[42,1029,1030,1032,1035,1038,1040,1042],{"class":44,"line":117},[42,1031,571],{"class":66},[42,1033,1034],{"class":70},": { ",[42,1036,1037],{"class":66},"class",[42,1039,482],{"class":70},[42,1041,938],{"class":199},[42,1043,1044],{"class":70}," },\n",[42,1046,1047,1049,1051,1053],{"class":44,"line":136},[42,1048,615],{"class":66},[42,1050,482],{"class":70},[42,1052,1000],{"class":199},[42,1054,1027],{"class":70},[42,1056,1057],{"class":44,"line":148},[42,1058,1059],{"class":48},"  \u002F\u002F ... 其他内部属性\n",[42,1061,1062],{"class":44,"line":153},[42,1063,344],{"class":70},[10,1065,1066],{},"h()和模板是有直接关系的，如果你在template模板里写了，最后编译阶段会产生渲染函数，其中dom结构就是依靠h()表示。",[33,1068,1070],{"className":35,"code":1069,"language":37,"meta":38,"style":38},"\u003C!-- 模板写法 -->\n\u003Ctemplate>\n  \u003Cdiv class=\"card\">\n    \u003Ch1>{{ title }}\u003C\u002Fh1>\n    \u003Cp>{{ content }}\u003C\u002Fp>\n  \u003C\u002Fdiv>\n\u003C\u002Ftemplate>\n\n\u003C!-- 编译后的渲染函数（简化） -->\n\u003Cscript>\nexport default {\n  setup() {\n    return () => h('div', { class: 'card' }, [\n      h('h1', this.title),\n      h('p', this.content)\n    ])\n  }\n}\n\u003C\u002Fscript>\n",[13,1071,1072,1083,1094,1112,1127,1140,1149,1158,1162,1171,1180,1185,1191,1218,1242,1262,1267,1271,1275],{"__ignoreMap":38},[42,1073,1074,1077,1080],{"class":44,"line":45},[42,1075,1076],{"class":55},"\u003C!--",[42,1078,1079],{"class":70}," 模板写法 ",[42,1081,1082],{"class":55},"-->\n",[42,1084,1085,1087,1091],{"class":44,"line":52},[42,1086,535],{"class":70},[42,1088,1090],{"class":1089},"s9eBZ","template",[42,1092,1093],{"class":70},">\n",[42,1095,1096,1099,1102,1105,1107,1110],{"class":44,"line":74},[42,1097,1098],{"class":70},"  \u003C",[42,1100,1101],{"class":1089},"div",[42,1103,1104],{"class":66}," class",[42,1106,142],{"class":55},[42,1108,1109],{"class":199},"\"card\"",[42,1111,1093],{"class":70},[42,1113,1114,1117,1120,1123,1125],{"class":44,"line":80},[42,1115,1116],{"class":70},"    \u003C",[42,1118,1119],{"class":1089},"h1",[42,1121,1122],{"class":70},">{{ title }}\u003C\u002F",[42,1124,1119],{"class":1089},[42,1126,1093],{"class":70},[42,1128,1129,1131,1133,1136,1138],{"class":44,"line":96},[42,1130,1116],{"class":70},[42,1132,10],{"class":1089},[42,1134,1135],{"class":70},">{{ content }}\u003C\u002F",[42,1137,10],{"class":1089},[42,1139,1093],{"class":70},[42,1141,1142,1145,1147],{"class":44,"line":111},[42,1143,1144],{"class":70},"  \u003C\u002F",[42,1146,1101],{"class":1089},[42,1148,1093],{"class":70},[42,1150,1151,1154,1156],{"class":44,"line":117},[42,1152,1153],{"class":70},"\u003C\u002F",[42,1155,1090],{"class":1089},[42,1157,1093],{"class":70},[42,1159,1160],{"class":44,"line":136},[42,1161,427],{"emptyLinePlaceholder":426},[42,1163,1164,1166,1169],{"class":44,"line":148},[42,1165,1076],{"class":55},[42,1167,1168],{"class":70}," 编译后的渲染函数（简化） ",[42,1170,1082],{"class":55},[42,1172,1173,1175,1178],{"class":44,"line":153},[42,1174,535],{"class":70},[42,1176,1177],{"class":1089},"script",[42,1179,1093],{"class":70},[42,1181,1182],{"class":44,"line":181},[42,1183,1184],{"class":70},"export default {\n",[42,1186,1187,1189],{"class":44,"line":187},[42,1188,786],{"class":66},[42,1190,789],{"class":70},[42,1192,1193,1195,1197,1199,1201,1203,1205,1208,1210,1212,1215],{"class":44,"line":212},[42,1194,99],{"class":66},[42,1196,796],{"class":70},[42,1198,465],{"class":55},[42,1200,801],{"class":66},[42,1202,86],{"class":70},[42,1204,806],{"class":199},[42,1206,1207],{"class":70},", { ",[42,1209,1037],{"class":89},[42,1211,563],{"class":55},[42,1213,1214],{"class":199}," 'card'",[42,1216,1217],{"class":70}," }, [\n",[42,1219,1220,1223,1225,1228,1230,1233,1236,1239],{"class":44,"line":234},[42,1221,1222],{"class":66},"      h",[42,1224,86],{"class":70},[42,1226,1227],{"class":199},"'h1'",[42,1229,128],{"class":70},[42,1231,1232],{"class":66},"this",[42,1234,1235],{"class":70},".",[42,1237,1238],{"class":66},"title",[42,1240,1241],{"class":70},"),\n",[42,1243,1244,1246,1248,1251,1253,1255,1257,1260],{"class":44,"line":258},[42,1245,1222],{"class":66},[42,1247,86],{"class":70},[42,1249,1250],{"class":199},"'p'",[42,1252,128],{"class":70},[42,1254,1232],{"class":66},[42,1256,1235],{"class":70},[42,1258,1259],{"class":66},"content",[42,1261,814],{"class":70},[42,1263,1264],{"class":44,"line":270},[42,1265,1266],{"class":70},"    ])\n",[42,1268,1269],{"class":44,"line":275},[42,1270,417],{"class":70},[42,1272,1273],{"class":44,"line":281},[42,1274,344],{"class":70},[42,1276,1278,1280,1282],{"class":44,"line":1277},19,[42,1279,1153],{"class":70},[42,1281,1177],{"class":1089},[42,1283,1093],{"class":70},[10,1285,1286],{},"h()就是用于生产VNode的工具，而patch()就是用于消费VNode的工具，用于首次渲染。当有数据变化的时候，就会用h 生成新的VNode。",[10,1288,1289],{},"patch也在runtime-core中，位置在src\u002Frenderer.ts中，他就是渲染器的核心哈数，完全不依赖浏览器。对于我们之前的感知，当有数据变化的时候就会让触发器完成effect的重新执行才对，为什么会有新的vnode产生呢，似乎有点不一样。",[10,1291,1292,1293,1296],{},"因为数据变化让effect重新执行渲染函数的时候就会",[18,1294,1295],{},"重新调用h","！",[33,1298,1300],{"className":720,"code":1299,"language":722,"meta":38,"style":38},"flowchart TD\n    A[\"修改数据\u003Cbr\u002F>count.value++\"]\n    B[\"trigger 依赖更新\"]\n    C[\"effect 重新执行\"]\n    D[\"执行渲染函数 render()\"]\n    E[\"调用 h() 生成新 VNode\"]\n    F[\"调用 patch(oldVNode, newVNode)\"]\n    G[\"diff 算法 + 批量 DOM 更新\"]\n    H[\"真实 DOM 更新\"]\n\n    A --> B --> C --> D --> E --> F --> G --> H\n",[13,1301,1302,1307,1312,1317,1322,1327,1332,1337,1342,1347,1351],{"__ignoreMap":38},[42,1303,1304],{"class":44,"line":45},[42,1305,1306],{},"flowchart TD\n",[42,1308,1309],{"class":44,"line":52},[42,1310,1311],{},"    A[\"修改数据\u003Cbr\u002F>count.value++\"]\n",[42,1313,1314],{"class":44,"line":74},[42,1315,1316],{},"    B[\"trigger 依赖更新\"]\n",[42,1318,1319],{"class":44,"line":80},[42,1320,1321],{},"    C[\"effect 重新执行\"]\n",[42,1323,1324],{"class":44,"line":96},[42,1325,1326],{},"    D[\"执行渲染函数 render()\"]\n",[42,1328,1329],{"class":44,"line":111},[42,1330,1331],{},"    E[\"调用 h() 生成新 VNode\"]\n",[42,1333,1334],{"class":44,"line":117},[42,1335,1336],{},"    F[\"调用 patch(oldVNode, newVNode)\"]\n",[42,1338,1339],{"class":44,"line":136},[42,1340,1341],{},"    G[\"diff 算法 + 批量 DOM 更新\"]\n",[42,1343,1344],{"class":44,"line":148},[42,1345,1346],{},"    H[\"真实 DOM 更新\"]\n",[42,1348,1349],{"class":44,"line":153},[42,1350,427],{"emptyLinePlaceholder":426},[42,1352,1353],{"class":44,"line":181},[42,1354,1355],{},"    A --> B --> C --> D --> E --> F --> G --> H\n",[1357,1358,1359],"style",{},"html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .s4XuR, html code.shiki .s4XuR{--shiki-default:#E36209;--shiki-dark:#FFAB70}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}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 .s9eBZ, html code.shiki .s9eBZ{--shiki-default:#22863A;--shiki-dark:#85E89D}",{"title":38,"searchDepth":52,"depth":52,"links":1361},[1362,1363],{"id":28,"depth":52,"text":28},{"id":389,"depth":52,"text":389,"children":1364},[1365],{"id":753,"depth":74,"text":753},"runtime-dom 是 Vue 3 源码中的一个核心包，它提供了与浏览器 DOM 相关的运行时功能。","md",{},"\u002Fvue\u002Fruntime-dom",{"description":1366},"Vue\u002Fruntime-dom","i1vsm6ERdX8zm3RqbveVTIWvDF1XaKloK5ZXzUjI0hM",1791042467930]