欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久

打開(kāi)APP
userphoto
未登錄

開(kāi)通VIP,暢享免費電子書(shū)等14項超值服

開(kāi)通VIP
都2020年了,我還不懂虛擬DOM

作者:小土豆biubiubiu

博客園:www.cnblogs.com/HouJiao/

掘金:juejin.im/user/243617…

微信公眾號:土豆媽的碎碎念(掃碼關(guān)注,一起吸貓,一起聽(tīng)故事,一起學(xué)習前端技術(shù))

作者文章的內容均來(lái)源于自己的實(shí)踐,如果覺(jué)得有幫助到你的話(huà),可以點(diǎn)贊給個(gè)鼓勵或留下寶貴意見(jiàn)

前言

2020年,vue3.0 betavue3 rc陸續發(fā)布,優(yōu)秀的人也早已開(kāi)始各種實(shí)踐新版本的新特性,而我還不懂虛擬DOM,所以趕緊跟學(xué)起來(lái)。

?? 黑發(fā)不知勤學(xué)早,白首方悔讀書(shū)也不遲

簡(jiǎn)單理解虛擬DOM

當我們打開(kāi)一個(gè)頁(yè)面,點(diǎn)擊查看元素,就能在開(kāi)發(fā)中工具中看到頁(yè)面對應的DOM節點(diǎn)。

假如我們將這些DOM節點(diǎn)使用一個(gè)js對象去表示,那這個(gè)js對象就可以被稱(chēng)之為虛擬DOM。

舉個(gè)栗子

下面有這樣一段DOM節點(diǎn)。

<div id='app' > <h3>內容</h3> <ul class='list'> <li>選項一</li> <li>選項二</li> </ul></div>復制代碼

我將這段DOM節點(diǎn)手動(dòng)轉化為一個(gè)JS對象。

vdom = {    type: 'div',  // 節點(diǎn)的類(lèi)型,也就是節點(diǎn)的標簽名    props: {      // 節點(diǎn)設置的所有屬性        'id': 'content'    },    children: [   // 當前節點(diǎn)的子節點(diǎn)        {            type: 'h3',            props: '',            children:['內容']        },        {            type: 'ul',            props: {                'class': 'list'            },            children: {                {                    type: 'li',                    props: '',                    children: ['選項一']                },                {                    type: 'li',                    props: '',                    children: ['選項二']                }            }        }    ]}復制代碼

手動(dòng)轉化出來(lái)的vdom對象就是我們所描述的虛擬DOM。

虛擬DOM的代碼實(shí)現

前面我們手動(dòng)將DOM節點(diǎn)轉化虛擬DOM,那這一節將使用代碼實(shí)現這個(gè)轉化。

項目環(huán)境搭建

本篇文章的示例使用npm進(jìn)行搭建,最終的一個(gè)目錄結構如下:

virtual-dom | dist webpack打包后的文件目錄 | node_modules | src 源代碼目錄 | index.html 測試的html文件 | index.js 打包的入口文件 | package-lock.json | package.json | webpack.config.js webpack配置文件復制代碼

定義虛擬DOM的數據結構

首先我們先將虛擬DOM的三個(gè)屬性定義出來(lái):type、props、children。

// 代碼位置:/virtual-dom/src/virtualDOM.js/**   @params: {String} type      標簽元素的類(lèi)型,也就是標簽名稱(chēng)*   @params: {Object} props     標簽元素設置的屬性*   @params: {Array}  children  標簽元素的子節點(diǎn)*/function VirtualDOM(type, props, children){    this.type = type;    this.props = props;    this.children = children;   }復制代碼

接著(zhù)定義一個(gè)創(chuàng )建虛擬dom的方法。

// 代碼位置:/virtual-dom/src/virtualDOM.js/** 創(chuàng )建虛擬DOM的方法* @method create* @return {VirtualDOM} 返回創(chuàng )建出來(lái)的虛擬DOM對象*/function create(type, props, children){ return new VirtualDOM(type, props, children)}export { VirtualDOM, create } 復制代碼

該方法用來(lái)創(chuàng )建虛擬DOM對象,這樣就不用我們每次都使用new關(guān)鍵字進(jìn)行創(chuàng )建

最后就是調用create方法,傳入對應的參數。

// 代碼位置:/virtual-dom/index.jsimport {create} from './src/virtualDOM'let vdom = create('div', {'class': 'content'}, [    create('h3', {}, ['內容']),    create('ul', { 'style': 'list-style-type: none;border: 1px solid;padding: 20px;'}, [                create('li', {}, ['選項一']),                create('li', {}, ['選項二'])    ])])console.log(vdom);復制代碼

最后我們看一下代碼生成的結果:

可以看到跟我們前面手動(dòng)轉化的vdom結果一致。

將虛擬DOM轉化為真實(shí)節點(diǎn)

虛擬DOM它實(shí)際就是存儲在內存中的一個(gè)數據,那終極目標是需要將這個(gè)數據轉化為真實(shí)的DOM節點(diǎn)展示到瀏覽器上,所以接下來(lái)我們再來(lái)實(shí)現一下將虛擬DOM轉化為真實(shí)的DOM節點(diǎn)。

將虛擬DOM轉化為真實(shí)節點(diǎn)的思路和步驟大致如下:

根據type屬性創(chuàng )建節點(diǎn) 設置節點(diǎn)屬性 處理子節點(diǎn):根據子節點(diǎn)的type創(chuàng )建子節點(diǎn)、設置子節點(diǎn)屬性,添加子節點(diǎn)到父節點(diǎn)中復制代碼

前兩個(gè)步驟很簡(jiǎn)單也很容易理解,最后一個(gè)步驟實(shí)際上是前兩個(gè)步驟的重復執行,因此最后一個(gè)步驟我們會(huì )使用遞歸進(jìn)行實(shí)現。

那么接下來(lái)就代碼實(shí)現一下。

根據type屬性創(chuàng )建節點(diǎn)

// 代碼位置:/virtual-dom/src/render.js/**   將虛擬節點(diǎn)轉化為真實(shí)的DOM節點(diǎn)并返回*   @method render*   @params {VirtualDOM}  vdom    虛擬DOM對象*   @return {HMTLElement} element 返回真實(shí)的DOM節點(diǎn) */function render(vdom){    var type = vdom.type;    var props = vdom.props;    var children = vdom.children;    // 根據type屬性創(chuàng  )建節點(diǎn)    var element = document.createElement(vdom.type);    return element;}export { render };復制代碼

這里我們將邏輯寫(xiě)在render函數中,并且返回創(chuàng )建好的真實(shí)DOM節點(diǎn)

設置節點(diǎn)屬性

// 代碼位置:/virtual-dom/src/render.js/* * 為DOM節點(diǎn)設置屬性* @method setProps* @params {HTMLElement} element dom元素* @params {Object} props 元素的屬性*/function setProps(element, props){ for (var key in props) { element.setAttribute(key,props[key]); }}export { render };復制代碼

設置節點(diǎn)的屬性這個(gè)功能由setProps函數實(shí)現

然后我們需要在render函數中調用setProps方法,實(shí)現節點(diǎn)屬性的設置。

// 代碼位置:/virtual-dom/src/render.js/**   將虛擬節點(diǎn)轉化為真實(shí)的DOM節點(diǎn)并返回*   @method render*   @params {VirtualDOM}  vdom    虛擬DOM對象*   @return {HMTLElement} element 返回真實(shí)的DOM節點(diǎn) */function render(vdom){    var type = vdom.type;    var props = vdom.props;    var children = vdom.children;    // 根據type屬性創(chuàng  )建節點(diǎn)    var element = document.createElement(vdom.type);    // 設置屬性    setProps(element, props);        return element;}/*  *   為DOM節點(diǎn)設置屬性*   @method setProps*   @params {HTMLElement} element  dom元素*   @params {Object}      props    元素的屬性*/function setProps(element, props){    for (var key in props) {        element.setAttribute(key,props[key]);    }}export { render };復制代碼

處理子節點(diǎn)

// 代碼位置:/virtual-dom/src/render.jsimport { VirtualDOM } from './virtualDOM';/** 將虛擬節點(diǎn)轉化為真實(shí)的DOM節點(diǎn)并返回* @method render* @params {VirtualDOM} vdom 虛擬DOM對象* @return {HMTLElement} element 返回真實(shí)的DOM節點(diǎn) */function render(vdom){ let type = vdom.type; let props = vdom.props; let children = vdom.children; // 根據type屬性創(chuàng )建節點(diǎn) let element = document.createElement(vdom.type); // 設置屬性 setProps(element, props); // 設置子節點(diǎn) children.forEach(child => { // 子節點(diǎn)是虛擬VirtualDOM的實(shí)例 遞歸創(chuàng )建節點(diǎn)、設置屬性 if(child instanceof VirtualDOM){ let childEle = render(child); }else{ // 子節點(diǎn)是文本 let childEle = document.createTextNode(child); } // 添加子節點(diǎn)到父節點(diǎn)中 element.appendChild(childEle); }); return element;}/* * 為DOM節點(diǎn)設置屬性* @method setProps* @params {HTMLElement} element dom元素* @params {Object} props 元素的屬性*/function setProps(element, props){ for (let key in props) { element.setAttribute(key,props[key]); }}export { render };復制代碼

在設置子節點(diǎn)的時(shí)候,有一個(gè)邏輯判斷:判斷子節點(diǎn)是否為虛擬VirtualDOM的實(shí)例,如果是的話(huà),則需要遞歸調用render函數處理子節點(diǎn);否則的話(huà)就說(shuō)明子節點(diǎn)是文本內容。這個(gè)判斷邏輯的處理是根據前面兩節虛擬DOM創(chuàng )建的結果而定的。

這塊邏輯判斷不是固定的寫(xiě)法,假如前面在生成虛擬DOM時(shí)文本類(lèi)型是另外一種表示方式,那這個(gè)邏輯判斷也就是另外一種寫(xiě)法了。

整合邏輯

那最后一步我們把前面的virtualDOM.jsrender.js整合到一起,實(shí)現真實(shí)DOM轉化為虛擬DOM,在將虛擬DOM轉化為真實(shí)DOM,最后在將生成后的真實(shí)DOM添加到頁(yè)面的body元素中。

// 代碼位置:/virtual-dom/index.jsimport { create} from './src/virtualDOM'import { render } from './src/render'// 創(chuàng  )建虛擬DOMlet vdom = create('div', {'class': 'content'}, [    create('h3', {}, ['內容']),    create('ul', { 'style': 'list-style-type: none;border: 1px solid;padding: 20px;'}, [                create('li', {}, ['選項一']),                create('li', {}, ['選項二'])    ])])// 將虛擬DOM轉化為真實(shí)DOMlet realdom = render(vdom);// 將真實(shí)DOM插入body元素中document.body.appendChild(realdom);復制代碼

最后瀏覽器中打開(kāi)這個(gè)index.html文件。

可以看到,由vdom轉化后的readldom插入到頁(yè)面后和原始的真實(shí)DOM是一樣的,說(shuō)明我們這個(gè)轉化是成功的。

dom-diff算法

前面總結了那么多關(guān)于虛擬DOM的內容,最后就是核心的dom-diff算法了。 dom-diff算法做的事情就是比較之前舊的虛擬DOM和當前新的虛擬DOM兩者之間的差異,然后將這部分差異的內容進(jìn)行更新到文檔中。

上文描述的差異稱(chēng)之為補?。?code>patches

那差異是怎么進(jìn)行比較的呢?回歸到我們的實(shí)現的虛擬DOM上。

/** @params: {String} type 標簽元素的類(lèi)型,也就是標簽名稱(chēng)* @params: {Object} props 標簽元素設置的屬性* @params: {Array} children 標簽元素的子節點(diǎn)*/function VirtualDOM(type, props, children){ this.type = type; this.props = props; this.children = children; }復制代碼

虛擬DOM對象最基本的就三個(gè)屬性:標簽類(lèi)型、標簽元素的屬性、標簽元素的子節點(diǎn),所以說(shuō)當兩個(gè)虛擬DOM對象進(jìn)行一個(gè)差異比較時(shí),比較的也就是這三個(gè)屬性。

那具體怎么個(gè)比較法呢,接下來(lái)我手動(dòng)比一比下面兩個(gè)虛擬DOM。

手動(dòng)比較出來(lái)oldDomnewDom這兩個(gè)的差異(patches):

這個(gè)是我們手動(dòng)比較出來(lái)的兩個(gè)DOM的差異,這些差異基本上包含了DOM屬性的變化、文本內容的變化、DOM節點(diǎn)的刪除以及替換。

這樣的比較結果使用一個(gè)js數據去表示,大概是這樣的結構:

patches = {    '0': [        {            type: 'props',   // 屬性發(fā)生變化            props: {                class: 'box',                id: 'wapper'            }        }    ],    '1': [        {          type: 'replace',   // 節點(diǎn)發(fā)生替換          content: {            type: 'h4',             {},             children: ['內容']           }        }    ],    '5':[        {            type: 'text',  // 文本內容變化            content: '內容一'        }    ],    '6': [        {            type: 'remove',  // 節點(diǎn)被移除        }    ]}復制代碼

這樣的比較結果也比較清晰明了,不過(guò)這個(gè)手動(dòng)的比較結果怎么用代碼去實(shí)現呢?這個(gè)就是我們大名鼎鼎的DOM-Diff算法。

DOM-diff算法發(fā)核心就是對虛擬DOM節點(diǎn)進(jìn)行深度優(yōu)先遍歷并對每一個(gè)虛擬DOM節點(diǎn)進(jìn)行編號,在遍歷的過(guò)程中對同一個(gè)層級的節點(diǎn)進(jìn)行比較,最終得到比較后的差異:patches。

注意dom-diff在比較差異時(shí)只會(huì )對同一層級的節點(diǎn)進(jìn)行比較,因為如果進(jìn)行完全的比較,算法實(shí)際復雜度會(huì )過(guò)高,所以舍棄了這種完全的比較方式,而采用同層比較(這里參考其他文章,因為算法不精,沒(méi)有具體研究過(guò))

那話(huà)不多說(shuō),我們這就來(lái)用代碼簡(jiǎn)單實(shí)現一下這個(gè)比較。

// 代碼位置:/virtual-dom/src/diff.js/** * @name: traversal * @description: 深度優(yōu)先遍歷虛擬DOM,計算出patches * @param {type} 參數 * @return {type} 返回值 */function traversal(oldNode, newNode, o, patches){ let currentPatches = []; if(newNode == undefined){ //節點(diǎn)被刪除 currentPatches.push({'type': 'remove'}); patches[o.nid] = currentPatches; }else if(oldNode instanceof VirtualDOM && newNode instanceof VirtualDOM){ // 如果是VirtualDOM類(lèi)型 if(oldNode.type != newNode.type){ // 節點(diǎn)發(fā)生替換 currentPatches.push({'type': 'replace', 'content': newNode.type}) patches[o.nid] = currentPatches; }else{ let resultDiff = diffProps(oldNode, newNode); // 屬性存在差異 if(Object.keys(resultDiff).length != 0){ currentPatches.push({'type': 'props', 'props': resultDiff}) patches[o.nid] = currentPatches; } } oldNode.children.forEach((element,index) => { o.nid++; traversal(element, newNode.children[index], o, patches); }); }else{ // 文本類(lèi)型 if(!diffText(oldNode, newNode)){ currentPatches.push({'type': 'text', 'content': newNode}); patches[o.nid] = currentPatches; } }}function diff(oldNode, newNode){ let patches = {}; //舊節點(diǎn)和新節點(diǎn)之間的差異結果 let o = {nid: 0}; // 節點(diǎn)的編號 // 遞歸遍歷oldNode、newNode 將差異結果保存到patches中 traversal(oldNode, newNode, o, patches) return patches;}export {diff};復制代碼

最后在index.js中調用這個(gè)方法,看看生成的patches是否正確。

// 創(chuàng  )建一個(gè)新的nodelet newNode = create('div', {'class': 'wapper', 'id': 'box'}, [    create('h4', {}, ['內容']),    create('ul', { 'style': 'list-style-type: none;border: 1px solid;padding: 20px;'}, [                create('li', {}, ['內容一'])    ])])let patches = diff(vdom, newNode);console.log('最終的patches');console.log(patches);復制代碼

最后我們將代碼生成的patches和手動(dòng)生成的patches進(jìn)行一個(gè)對比,看看結果是否一樣。

可以看到兩者是一樣的,所以證明我們的diff是成功實(shí)現了。

將patches應用到頁(yè)面中

到此我簡(jiǎn)單畫(huà)個(gè)圖總結一下前面我們已經(jīng)完成的功能。

那我們的最后一步就是將diff出來(lái)的patches應用到realdom上。

這里呢,我先直接將代碼貼出來(lái)。

// 代碼位置:/virtual-dom/src/patch.jsimport {render} from './render'/** * @name: walk * @description: 遍歷patches 將差異應用到真實(shí)的DOM節點(diǎn)上 * @param {HTMLElement} 真實(shí)的DOM節點(diǎn) * @param {Object} 虛擬節點(diǎn)的編號 編號從0開(kāi)始,從patches中獲取編號為o.nid的虛擬DOM的差異 * @param {Object} 使用diff算法比較出來(lái)新的虛擬節點(diǎn)和舊的虛擬節點(diǎn)的差異 */function walk(realdom, o, patchs){ // 獲取當前節點(diǎn)的差異 const currentPatch = patchs[o.nid]; // 對當前節點(diǎn)進(jìn)行DOM操作 if (currentPatch) { applyPatch(realdom, currentPatch) } for(let i=0; i < realdom.childNodes.length; i++){ let childNode = realdom.childNodes[i]; o.nid++; walk(childNode, o, patchs); }}/** * @name: applyPatch * @description: 應用差異到真實(shí)節點(diǎn)上 * @param {HTMLElement} 需要更新的真實(shí)DOM節點(diǎn) * @param {Array} 節點(diǎn)需要更新的內容 */function applyPatch(currentRealNode, currentPatch){ currentPatch.forEach(patch => { const type = patch['type']; switch(type){ case 'props': const props = patch['props']; for(const propKey in props){ currentRealNode.setAttribute(propKey, props[propKey]) } break; case 'replace': let content = patch['content']; let newEle = null; if(typeof(content) == 'string'){ newEle = document.createTextNode(content); }else{ // 調用render將替換的節點(diǎn)渲染成真實(shí)的dom newEle = render(content); } currentRealNode.parentNode.replaceChild(newEle, currentRealNode); break; case 'text': currentRealNode.textContent = patch['content'] break; case 'remove': currentRealNode.parentNode.removeChild(currentRealNode) } });}export {walk};復制代碼

接下來(lái)我們就分析一下patch.js中的代碼。

applyPatch

applyPatch函數的功能就是將差異對象應用到真實(shí)的DOM節點(diǎn)上。

函數的兩個(gè)參數為:currentRealNodecurrentPatch,分別表示的是需要更新的真實(shí)DOM節點(diǎn)節點(diǎn)需要更新的內容。

舉個(gè)例子,如下:

前面我們生成的patches共有四種不同的類(lèi)型,分別為:節點(diǎn)屬性變化、節點(diǎn)類(lèi)型被替換、節點(diǎn)被移除、節點(diǎn)文本內容變化,所以在applyPatch函數中使用switch語(yǔ)句分別處理這四種不同的情況。

節點(diǎn)屬性發(fā)生變化
我們只需要將新的屬性(patch['props'])設置到當前節點(diǎn)上即可。  復制代碼
節點(diǎn)類(lèi)型被替換
節點(diǎn)類(lèi)型被替換以后,我們的patch['type']值為'replace',對應的patch['content']為替換后虛擬DOM節點(diǎn)。對于我們這篇文章中的示例來(lái)說(shuō),當執行到h3節點(diǎn)的時(shí)候,currentPatch的值為:復制代碼
    [        {          type: 'replace',   // 節點(diǎn)發(fā)生替換          content: {            type: 'h4',             {},             children: ['內容']           }        }    ]復制代碼
所以我們需要將patch['content']這個(gè)虛擬節點(diǎn)轉化為真實(shí)的節點(diǎn),更新到整個(gè)文檔節點(diǎn)中。復制代碼

由于本次我們的示例將h3節點(diǎn)替換成了h4,實(shí)際上有可能替換成文本內容,在replace的邏輯中會(huì )patch['content']的類(lèi)型做了判斷,如果替換成文本內容,則只需要創(chuàng )建文本節點(diǎn)即可。

節點(diǎn)文本內容變化
節點(diǎn)文本內容發(fā)生變化,只需要為文本節點(diǎn)的textContet屬性賦新值即可。復制代碼
節點(diǎn)被移除
節點(diǎn)被移除,調用當前節點(diǎn)的父級節點(diǎn)的removeChild移除當前節點(diǎn)即可。復制代碼

applyPatch方法內部都是一些操作原生DOM節點(diǎn)的邏輯

總結

到此本篇文章就結束了,在此我們做一個(gè)簡(jiǎn)單的總結。

關(guān)于什么是虛擬DOM

將真實(shí)的DOM節點(diǎn)抽象成為一個(gè)js對象,這個(gè)js對象就稱(chēng)之為是虛擬DOM。

關(guān)于dom-diff算法

dom-diff算法核心的幾個(gè)點(diǎn)就是:

1.將真實(shí)的DOM節點(diǎn)使用虛擬DOM表示(create)  2.將虛擬DOM渲染到瀏覽器頁(yè)面上(render)  3.當用戶(hù)操作界面修改數據后,會(huì )生成一個(gè)新的虛擬DOM,將新的虛擬DOM和舊的虛擬DOM進(jìn)行對比,生成差異對象patches(diff)  4.將差異對象應用到真實(shí)的DOM節點(diǎn)上(patch)  復制代碼

為什么需要虛擬DOM

那在了解了虛擬DOM以及和虛擬DOM相關(guān)的dom-diff算法以后,我們肯定會(huì )思考為什么需要虛擬DOM這樣的東西。

原因一

虛擬DOM基于JavaScript對象,而真實(shí)的DOM要基于瀏覽器平臺,所以虛擬DOM可以跨平臺使用。

原因二:提高操作DOM的性能

我們都知道瀏覽器將一個(gè)HTML文檔轉化為真實(shí)的內容呈現到瀏覽器上的整個(gè)過(guò)程是需要經(jīng)歷一系列的步驟:構建DOM樹(shù)、構建CSS規則樹(shù)、基于DOM樹(shù)CSS規則樹(shù)構建呈現樹(shù)(呈現樹(shù)是文檔的可視化表示)、根據呈現樹(shù)進(jìn)行布局繪制。當有用戶(hù)交互需要改變文檔結構時(shí),很大程度上會(huì )再一次觸發(fā)這一系列的操作。

假如用戶(hù)在一次交互中修改了10次DOM結構,那么就會(huì )觸發(fā)10次上述的步驟,所以說(shuō)操作DOM的代價(jià)是很大的。

所以我們使用一個(gè)js對象來(lái)表示真實(shí)的DOM,當用戶(hù)在一次交互中修改了10DOM結構時(shí),我們就可以將這10次的修改映射到這個(gè)js對象,之后比較之前的虛擬DOM和修改后的虛擬DOM,最后在將比較的差異應用到文檔中。那這樣的操作顯然會(huì )比直接更新10次真實(shí)的DOM要節省性能。

最后

本篇文章只針對虛擬DOMdom-diff做了簡(jiǎn)單的總結和實(shí)踐,而vue框架內部在diff的時(shí)候還有一些更細節的處理,后續在vue源碼學(xué)習時(shí)會(huì )在做總結。

示例代碼

本文的源代碼可以 戳這里 獲取

參考文章

深入剖析:Vue核心之虛擬DOM
讓虛擬DOM和DOM-diff不再成為你的絆腳石
vue核心之虛擬DOM(vdom)
詳解Vue中的虛擬DOM

關(guān)于

作者

小土豆biubiubiu

一個(gè)努力學(xué)習的前端小菜鳥(niǎo),知識是無(wú)限的。堅信只要不停下學(xué)習的腳步,總能到達自己期望的地方

同時(shí)還是一個(gè)喜歡小貓咪的人,家里有一只美短小母貓,名叫土豆

博客園

www.cnblogs.com/HouJiao/

掘金

juejin.im/user/243617…

微信公眾號

土豆媽的碎碎念

微信公眾號的初衷是記錄自己和身邊的一些故事,同時(shí)會(huì )不定期更新一些技術(shù)文章

歡迎大家掃碼關(guān)注,一起吸貓,一起聽(tīng)故事,一起學(xué)習前端技術(shù)

作者寄語(yǔ)

小小總結,歡迎大家指導~

本站僅提供存儲服務(wù),所有內容均由用戶(hù)發(fā)布,如發(fā)現有害或侵權內容,請點(diǎn)擊舉報。
打開(kāi)APP,閱讀全文并永久保存 查看更多類(lèi)似文章
猜你喜歡
類(lèi)似文章
vue3.0 diff算法詳解(超詳細)
9道價(jià)值20k薪資的“VUE必備面試題”,收藏不虧!
越來(lái)越受歡迎的Vue想學(xué)么,90后小姐姐今兒來(lái)教你
詳解Vue中的虛擬DOM
實(shí)現虛擬DOM
如何選擇 Web 前端模板引擎?
更多類(lèi)似文章 >>
生活服務(wù)
分享 收藏 導長(cháng)圖 關(guān)注 下載文章
綁定賬號成功
后續可登錄賬號暢享VIP特權!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服

欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久