[{"data":1,"prerenderedAt":772},["ShallowReactive",2],{"page-\u002Fvue\u002Fvue中虚拟dom的理解":3},{"id":4,"title":5,"body":6,"description":764,"extension":765,"meta":766,"navigation":767,"path":768,"seo":769,"stem":770,"__hash__":771},"content\u002FVue\u002FVue中虚拟DOM的理解.md","Vue中虚拟DOM的理解",{"type":7,"value":8,"toc":758},"minimark",[9,13,40,44,50,132,202,389,473,627,630,735,738,745,748,754],[10,11,5],"h1",{"id":12},"vue中虚拟dom的理解",[14,15,16,20,21,24,25,28,29,32,33,35,36,39],"p",{},[17,18,19],"code",{},"Virtual DOM","是一棵以",[17,22,23],{},"JavaScript","对象作为基础的树，每一个节点称为",[17,26,27],{},"VNode","，用对象属性来描述节点，实际上它是一层对真实",[17,30,31],{},"DOM","的抽象，最终可以通过渲染操作使这棵树映射到真实环境上，简单来说",[17,34,19],{},"就是一个",[17,37,38],{},"Js","对象，用以描述整个文档。",[41,42,43],"h2",{"id":43},"描述",[14,45,46,47,49],{},"在浏览器中构建页面时需要使用",[17,48,31],{},"节点描述整个文档。",[51,52,57],"pre",{"className":53,"code":54,"language":55,"meta":56,"style":56},"language-html shiki shiki-themes github-light github-dark","\u003Cdiv class=\"root\" name=\"root\">\n    \u003Cp>1\u003C\u002Fp>\n    \u003Cdiv>11\u003C\u002Fdiv>\n\u003C\u002Fdiv>\n","html","",[17,58,59,93,108,122],{"__ignoreMap":56},[60,61,64,68,72,76,79,83,86,88,90],"span",{"class":62,"line":63},"line",1,[60,65,67],{"class":66},"sVt8B","\u003C",[60,69,71],{"class":70},"s9eBZ","div",[60,73,75],{"class":74},"sScJk"," class",[60,77,78],{"class":66},"=",[60,80,82],{"class":81},"sZZnC","\"root\"",[60,84,85],{"class":74}," name",[60,87,78],{"class":66},[60,89,82],{"class":81},[60,91,92],{"class":66},">\n",[60,94,96,99,101,104,106],{"class":62,"line":95},2,[60,97,98],{"class":66},"    \u003C",[60,100,14],{"class":70},[60,102,103],{"class":66},">1\u003C\u002F",[60,105,14],{"class":70},[60,107,92],{"class":66},[60,109,111,113,115,118,120],{"class":62,"line":110},3,[60,112,98],{"class":66},[60,114,71],{"class":70},[60,116,117],{"class":66},">11\u003C\u002F",[60,119,71],{"class":70},[60,121,92],{"class":66},[60,123,125,128,130],{"class":62,"line":124},4,[60,126,127],{"class":66},"\u003C\u002F",[60,129,71],{"class":70},[60,131,92],{"class":66},[14,133,134,135,137,138,141,142,144,145,148,149,148,152,148,155,148,158,148,161,148,164,148,167,148,170,148,173,148,176,148,179,148,182,148,185,148,188,148,191,194,195,197,198,201],{},"如果使用",[17,136,38],{},"对象去描述上述的节点以及文档，那么便类似于下面的样子，当然这不是",[17,139,140],{},"Vue","中用以描述节点的对象，",[17,143,140],{},"中用以描述一个节点的对象包括大量属性，例如",[17,146,147],{},"tag","、",[17,150,151],{},"data",[17,153,154],{},"children",[17,156,157],{},"text",[17,159,160],{},"elm",[17,162,163],{},"ns",[17,165,166],{},"context",[17,168,169],{},"key",[17,171,172],{},"componentOptions",[17,174,175],{},"componentInstance",[17,177,178],{},"parent",[17,180,181],{},"raw",[17,183,184],{},"isStatic",[17,186,187],{},"isRootInsert",[17,189,190],{},"isComment",[17,192,193],{},"isCloned","等等，具体的属性可以参阅",[17,196,140],{},"源码的",[17,199,200],{},"\u002Fdev\u002Fsrc\u002Fcore\u002Fvdom\u002Fvnode.js","。",[51,203,207],{"className":204,"code":205,"language":206,"meta":56,"style":56},"language-javascript shiki shiki-themes github-light github-dark","{\n    type: \"tag\",\n    tagName: \"div\",\n    attr: {\n        className: \"root\"\n        name: \"root\"\n    },\n    parent: null,\n    children: [{\n        type: \"tag\",\n        tagName: \"p\",\n        attr: {},\n        parent: {} \u002F* 父节点的引用 *\u002F, \n        children: [{\n            type: \"text\",\n            tagName: \"text\",\n            parent: {} \u002F* 父节点的引用 *\u002F, \n            content: \"1\"\n        }]\n    },{\n        type: \"tag\",\n        tagName: \"div\",\n        attr: {},\n        parent: {} \u002F* 父节点的引用 *\u002F, \n        children: [{\n            type: \"text\",\n            tagName: \"text\",\n            parent: {} \u002F* 父节点的引用 *\u002F, \n            content: \"11\"\n        }]\n    }]\n}\n","javascript",[17,208,209,214,219,224,229,235,241,247,253,259,265,271,277,283,289,295,301,307,313,319,325,330,336,341,346,351,356,361,366,372,377,383],{"__ignoreMap":56},[60,210,211],{"class":62,"line":63},[60,212,213],{},"{\n",[60,215,216],{"class":62,"line":95},[60,217,218],{},"    type: \"tag\",\n",[60,220,221],{"class":62,"line":110},[60,222,223],{},"    tagName: \"div\",\n",[60,225,226],{"class":62,"line":124},[60,227,228],{},"    attr: {\n",[60,230,232],{"class":62,"line":231},5,[60,233,234],{},"        className: \"root\"\n",[60,236,238],{"class":62,"line":237},6,[60,239,240],{},"        name: \"root\"\n",[60,242,244],{"class":62,"line":243},7,[60,245,246],{},"    },\n",[60,248,250],{"class":62,"line":249},8,[60,251,252],{},"    parent: null,\n",[60,254,256],{"class":62,"line":255},9,[60,257,258],{},"    children: [{\n",[60,260,262],{"class":62,"line":261},10,[60,263,264],{},"        type: \"tag\",\n",[60,266,268],{"class":62,"line":267},11,[60,269,270],{},"        tagName: \"p\",\n",[60,272,274],{"class":62,"line":273},12,[60,275,276],{},"        attr: {},\n",[60,278,280],{"class":62,"line":279},13,[60,281,282],{},"        parent: {} \u002F* 父节点的引用 *\u002F, \n",[60,284,286],{"class":62,"line":285},14,[60,287,288],{},"        children: [{\n",[60,290,292],{"class":62,"line":291},15,[60,293,294],{},"            type: \"text\",\n",[60,296,298],{"class":62,"line":297},16,[60,299,300],{},"            tagName: \"text\",\n",[60,302,304],{"class":62,"line":303},17,[60,305,306],{},"            parent: {} \u002F* 父节点的引用 *\u002F, \n",[60,308,310],{"class":62,"line":309},18,[60,311,312],{},"            content: \"1\"\n",[60,314,316],{"class":62,"line":315},19,[60,317,318],{},"        }]\n",[60,320,322],{"class":62,"line":321},20,[60,323,324],{},"    },{\n",[60,326,328],{"class":62,"line":327},21,[60,329,264],{},[60,331,333],{"class":62,"line":332},22,[60,334,335],{},"        tagName: \"div\",\n",[60,337,339],{"class":62,"line":338},23,[60,340,276],{},[60,342,344],{"class":62,"line":343},24,[60,345,282],{},[60,347,349],{"class":62,"line":348},25,[60,350,288],{},[60,352,354],{"class":62,"line":353},26,[60,355,294],{},[60,357,359],{"class":62,"line":358},27,[60,360,300],{},[60,362,364],{"class":62,"line":363},28,[60,365,306],{},[60,367,369],{"class":62,"line":368},29,[60,370,371],{},"            content: \"11\"\n",[60,373,375],{"class":62,"line":374},30,[60,376,318],{},[60,378,380],{"class":62,"line":379},31,[60,381,382],{},"    }]\n",[60,384,386],{"class":62,"line":385},32,[60,387,388],{},"}\n",[14,390,391,392,394,395,398,399,402,403,406,407,148,410,413,414,417,418,420,421,423,424,426,427,398,429,432,433,435,436,439,440,442,443,445,446,448,449,451,452,454,455,458,459,462,463,466,467,470,471,201],{},"在",[17,393,140],{},"中首先会解析",[17,396,397],{},"template","中定义的",[17,400,401],{},"HTML","节点以及组件节点，为",[17,404,405],{},"render","作准备，在解析的过程中会生成",[17,408,409],{},"_c()",[17,411,412],{},"_v()","等函数，其作为",[17,415,416],{},"renderHelpers","用以创建节点，",[17,419,412],{},"函数就是用以创建文本节点，而",[17,422,409],{},"函数就是用以创建",[17,425,27],{},"节点的，这个函数其实就是",[17,428,140],{},[17,430,431],{},"_createElement()","函数，通过这个函数来确定创建的是普通节点还是组件节点，具体可以在",[17,434,140],{},"源码中",[17,437,438],{},"\u002Fdev\u002Fsrc\u002Fcore\u002Fvdom\u002Fcreate-element.js","以及",[17,441,438],{},"查阅，当解析完成之后，便能够生成",[17,444,405],{},"函数，而当",[17,447,405],{},"函数执行后便返回了",[17,450,27],{},"节点组成的虚拟",[17,453,31],{},"树，树中的每一颗节点都会存储渲染的时候需要的信息，之后便是通过",[17,456,457],{},"diff","算法以及",[17,460,461],{},"patch","过程的",[17,464,465],{},"createElm","或",[17,468,469],{},"patchVnode","渲染到真实",[17,472,31],{},[51,474,476],{"className":204,"code":475,"language":206,"meta":56,"style":56},"if (typeof tag === 'string') {\nlet Ctor\nns = (context.$vnode && context.$vnode.ns) || config.getTagNamespace(tag)\nif (config.isReservedTag(tag)) {\n  \u002F\u002F platform built-in elements\n  if (process.env.NODE_ENV !== 'production' && isDef(data) && isDef(data.nativeOn)) {\n    warn(\n      `The .native modifier for v-on is only valid on components but it was used on \u003C${tag}>.`,\n      context\n    )\n  }\n  vnode = new VNode(\n    config.parsePlatformTagName(tag), data, children,\n    undefined, undefined, context\n  )\n} else if ((!data || !data.pre) && isDef(Ctor = resolveAsset(context.$options, 'components', tag))) {\n  \u002F\u002F component\n  vnode = createComponent(Ctor, data, context, children, tag)\n} else {\n  \u002F\u002F unknown or unlisted namespaced elements\n  \u002F\u002F check at runtime because it may get assigned a namespace when its\n  \u002F\u002F parent normalizes children\n  vnode = new VNode(\n    tag, data, children,\n    undefined, undefined, context\n  )\n}\n} else {\n\u002F\u002F direct component options \u002F constructor\nvnode = createComponent(tag, data, context, children)\n}\n",[17,477,478,483,488,493,498,503,508,513,518,523,528,533,538,543,548,553,558,563,568,573,578,583,588,592,597,601,605,609,613,618,623],{"__ignoreMap":56},[60,479,480],{"class":62,"line":63},[60,481,482],{},"if (typeof tag === 'string') {\n",[60,484,485],{"class":62,"line":95},[60,486,487],{},"let Ctor\n",[60,489,490],{"class":62,"line":110},[60,491,492],{},"ns = (context.$vnode && context.$vnode.ns) || config.getTagNamespace(tag)\n",[60,494,495],{"class":62,"line":124},[60,496,497],{},"if (config.isReservedTag(tag)) {\n",[60,499,500],{"class":62,"line":231},[60,501,502],{},"  \u002F\u002F platform built-in elements\n",[60,504,505],{"class":62,"line":237},[60,506,507],{},"  if (process.env.NODE_ENV !== 'production' && isDef(data) && isDef(data.nativeOn)) {\n",[60,509,510],{"class":62,"line":243},[60,511,512],{},"    warn(\n",[60,514,515],{"class":62,"line":249},[60,516,517],{},"      `The .native modifier for v-on is only valid on components but it was used on \u003C${tag}>.`,\n",[60,519,520],{"class":62,"line":255},[60,521,522],{},"      context\n",[60,524,525],{"class":62,"line":261},[60,526,527],{},"    )\n",[60,529,530],{"class":62,"line":267},[60,531,532],{},"  }\n",[60,534,535],{"class":62,"line":273},[60,536,537],{},"  vnode = new VNode(\n",[60,539,540],{"class":62,"line":279},[60,541,542],{},"    config.parsePlatformTagName(tag), data, children,\n",[60,544,545],{"class":62,"line":285},[60,546,547],{},"    undefined, undefined, context\n",[60,549,550],{"class":62,"line":291},[60,551,552],{},"  )\n",[60,554,555],{"class":62,"line":297},[60,556,557],{},"} else if ((!data || !data.pre) && isDef(Ctor = resolveAsset(context.$options, 'components', tag))) {\n",[60,559,560],{"class":62,"line":303},[60,561,562],{},"  \u002F\u002F component\n",[60,564,565],{"class":62,"line":309},[60,566,567],{},"  vnode = createComponent(Ctor, data, context, children, tag)\n",[60,569,570],{"class":62,"line":315},[60,571,572],{},"} else {\n",[60,574,575],{"class":62,"line":321},[60,576,577],{},"  \u002F\u002F unknown or unlisted namespaced elements\n",[60,579,580],{"class":62,"line":327},[60,581,582],{},"  \u002F\u002F check at runtime because it may get assigned a namespace when its\n",[60,584,585],{"class":62,"line":332},[60,586,587],{},"  \u002F\u002F parent normalizes children\n",[60,589,590],{"class":62,"line":338},[60,591,537],{},[60,593,594],{"class":62,"line":343},[60,595,596],{},"    tag, data, children,\n",[60,598,599],{"class":62,"line":348},[60,600,547],{},[60,602,603],{"class":62,"line":353},[60,604,552],{},[60,606,607],{"class":62,"line":358},[60,608,388],{},[60,610,611],{"class":62,"line":363},[60,612,572],{},[60,614,615],{"class":62,"line":368},[60,616,617],{},"\u002F\u002F direct component options \u002F constructor\n",[60,619,620],{"class":62,"line":374},[60,621,622],{},"vnode = createComponent(tag, data, context, children)\n",[60,624,625],{"class":62,"line":379},[60,626,388],{},[41,628,629],{"id":629},"作用",[14,631,632,633,635,636,638,639,641,642,644,645,647,648,650,651,653,654,657,658,660,661,663,664,666,667,669,670,672,673,675,676,678,679,681,682,685,686,689,690,693,694,696,697,699,700,702,703,201,705,707,708,710,711,713,714,716,717,719,720,722,723,725,726,728,729,731,732,734],{},"渲染真实",[17,634,31],{},"的过程中开销是很大的，例如当有时候修改了某个数据或者属性，如果直接渲染到真实",[17,637,31],{},"上可能会引起整个",[17,640,31],{},"树的重绘与回流，而",[17,643,457],{},"算法能够只更新修改的那部分",[17,646,31],{},"结构而不更新整个",[17,649,31],{},"，这里需要说明的是操作",[17,652,31],{},"结构的速度并不慢，而性能消耗主要是在浏览器重绘与回流的操作上。",[655,656],"br",{},"\n当选用",[17,659,457],{},"算法进行部分更新的时候就需要比较旧",[17,662,31],{},"结构与新",[17,665,31],{},"结构的不同，此时就需要",[17,668,27],{},"来描述整个",[17,671,31],{},"结构，首先根据真实",[17,674,31],{},"生成",[17,677,19],{},"，当",[17,680,19],{},"某个节点的数据改变后会生成一个新的",[17,683,684],{},"Vnode","，然后通过",[17,687,688],{},"newVNode","和",[17,691,692],{},"oldVNode","进行对比，发现有不同之处便进行",[17,695,461],{},"修改于真实",[17,698,31],{},"，然后使旧的",[17,701,19],{},"赋值为新的",[17,704,19],{},[655,706],{},"\n简单来说建立",[17,709,19],{},"的目的是减少对于整个",[17,712,31],{},"的操作，通过建立",[17,715,19],{},"来追踪如何改变真实",[17,718,31],{},"，从而实现更高效地更新节点。",[655,721],{},"\n使用",[17,724,19],{},"同样也是有部分缺点，代码更多，体积更大，内存占用增大，对于小量的单一的",[17,727,31],{},"修改使用虚拟",[17,730,31],{},"成本反而更高，但是整体来说，使用",[17,733,19],{},"是优点远大于缺点的。",[41,736,737],{"id":737},"每日一题",[51,739,743],{"className":740,"code":742,"language":157},[741],"language-text","https:\u002F\u002Fgithub.com\u002FWindrunnerMax\u002FEveryDay\n",[17,744,742],{"__ignoreMap":56},[41,746,747],{"id":747},"参考",[51,749,752],{"className":750,"code":751,"language":157},[741],"https:\u002F\u002Fjuejin.im\u002Fpost\u002F6844903607913938951\nhttps:\u002F\u002Fsegmentfault.com\u002Fa\u002F1190000018211084\nhttps:\u002F\u002Fgithub.com\u002Flihongxun945\u002Fmyblog\u002Fissues\u002F32\nhttps:\u002F\u002Fcloud.tencent.com\u002Fdeveloper\u002Farticle\u002F1004551\nhttps:\u002F\u002Fwww.cnblogs.com\u002Ffundebug\u002Fp\u002Fvue-virtual-dom.html\nhttps:\u002F\u002Fblog.csdn.net\u002Fu010692018\u002Farticle\u002Fdetails\u002F78799335\u002F\n",[17,753,751],{"__ignoreMap":56},[755,756,757],"style",{},"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 .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .s9eBZ, html code.shiki .s9eBZ{--shiki-default:#22863A;--shiki-dark:#85E89D}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}",{"title":56,"searchDepth":95,"depth":95,"links":759},[760,761,762,763],{"id":43,"depth":95,"text":43},{"id":629,"depth":95,"text":629},{"id":737,"depth":95,"text":737},{"id":747,"depth":95,"text":747},"Virtual DOM是一棵以JavaScript对象作为基础的树，每一个节点称为VNode，用对象属性来描述节点，实际上它是一层对真实DOM的抽象，最终可以通过渲染操作使这棵树映射到真实环境上，简单来说Virtual DOM就是一个Js对象，用以描述整个文档。","md",{},true,"\u002Fvue\u002Fvue中虚拟dom的理解",{"title":5,"description":764},"Vue\u002FVue中虚拟DOM的理解","VdULtM_yuYkTCyttFxqKLuwUApLTg9vtuNvcXa-Wz50",1791042470535]