国产99久久精品_欧美日本韩国一区二区_激情小说综合网_欧美一级二级视频_午夜av电影_日本久久精品视频

最新文章專題視頻專題問答1問答10問答100問答1000問答2000關鍵字專題1關鍵字專題50關鍵字專題500關鍵字專題1500TAG最新視頻文章推薦1 推薦3 推薦5 推薦7 推薦9 推薦11 推薦13 推薦15 推薦17 推薦19 推薦21 推薦23 推薦25 推薦27 推薦29 推薦31 推薦33 推薦35 推薦37視頻文章20視頻文章30視頻文章40視頻文章50視頻文章60 視頻文章70視頻文章80視頻文章90視頻文章100視頻文章120視頻文章140 視頻2關鍵字專題關鍵字專題tag2tag3文章專題文章專題2文章索引1文章索引2文章索引3文章索引4文章索引5123456789101112131415文章專題3
問答文章1 問答文章501 問答文章1001 問答文章1501 問答文章2001 問答文章2501 問答文章3001 問答文章3501 問答文章4001 問答文章4501 問答文章5001 問答文章5501 問答文章6001 問答文章6501 問答文章7001 問答文章7501 問答文章8001 問答文章8501 問答文章9001 問答文章9501
當前位置: 首頁 - 科技 - 知識百科 - 正文

深入理解Vue2.x的虛擬DOM diff原理

來源:懂視網 責編:小采 時間:2020-11-27 22:28:54
文檔

深入理解Vue2.x的虛擬DOM diff原理

深入理解Vue2.x的虛擬DOM diff原理:前言 經常看到講解Vue2的虛擬Dom diff原理的,但很多都是在原代碼的基礎上添加些注釋等等,這里從0行代碼開始實現一個Vue2的虛擬DOM 實現VNode src/core/vdom/Vnode.js export class VNode{ constructor ( tag, //標簽名 c
推薦度:
導讀深入理解Vue2.x的虛擬DOM diff原理:前言 經常看到講解Vue2的虛擬Dom diff原理的,但很多都是在原代碼的基礎上添加些注釋等等,這里從0行代碼開始實現一個Vue2的虛擬DOM 實現VNode src/core/vdom/Vnode.js export class VNode{ constructor ( tag, //標簽名 c

前言

經常看到講解Vue2的虛擬Dom diff原理的,但很多都是在原代碼的基礎上添加些注釋等等,這里從0行代碼開始實現一個Vue2的虛擬DOM

實現VNode

src/core/vdom/Vnode.js

export class VNode{
 constructor (
 tag, //標簽名
 children,//孩子[VNode,VNode],
 text, //文本節點
 elm //對應的真實dom對象
 ){
 this.tag = tag;
 this.children = children
 this.text = text;
 this.elm = elm;
 }
}
export function createTextNode(val){
 //為什么這里默認把elm置為undefined,不直接根據tag 用document.createElement(tagName)把elm賦值?而要等后面createElm時候再賦值呢?
 return new VNode(undefined,undefined,String(val),undefined)
}
export function createCommentNode(tag,children){
 if(children){
 for(var i=0;i<children.length;i++){
 var child = children[i];
 if(typeof child == 'string'){
 children[i] = createTextNode(child)
 }
 }
 }
 return new VNode(tag,children,undefined,null)
}

定義一個Vnode類, 創建節點分為兩類,一類為text節點,一類非text節點

src/main.js

import {VNode,createCommentNode} from './core/vdom/vnode'
var newVonde = createCommentNode('ul',[createCommentNode('li',['item 1']),createCommentNode('li',['item 2']),createCommentNode('li',['item 3'])])

在main.js就可以根據Vnode 生成對應的Vnode對象,上述代碼對應的dom表示

<ul>

<li>item1</li>
<li>item2</li>
<li>item3</li>
</ul>

先實現不用diff把Vnode渲染到頁面中來

為什么先來實現不用diff渲染Vnode的部分,這里也是為了統計渲染的時間,來表明一個道理。并不是diff就比非diff要開,虛擬DOM并不是任何時候性能都比非虛擬DOM 要快

先來實現一個工具函數,不熟悉的人可以手工敲下代碼 熟悉下

// 真實的dom操作
// src/core/vdom/node-ops.js

export function createElement (tagName) {
 return document.createElement(tagName)
}

export function createTextNode (text) {
 return document.createTextNode(text)
}

export function createComment (text) {
 return document.createComment(text)
}

export function insertBefore (parentNode, newNode, referenceNode) {
 parentNode.insertBefore(newNode, referenceNode)
}

export function removeChild (node, child) {
 node.removeChild(child)
}

export function appendChild (node, child) {
 node.appendChild(child)
}

export function parentNode (node) {
 return node.parentNode
}

export function nextSibling (node) {
 return node.nextSibling
}

export function tagName (node) {
 return node.tagName
}

export function setTextContent (node, text) {
 node.textContent = text
}

export function setAttribute (node, key, val) {
 node.setAttribute(key, val)
}

src/main.js

import {VNode,createCommentNode} from './core/vdom/vnode'
import patch from './core/vdom/patch'


var container = document.getElementById("app");
var oldVnode = new VNode(container.tagName,[],undefined,container);
var newVonde = createCommentNode('ul',[createCommentNode('li',['item 1']),createCommentNode('li',['item 2']),createCommentNode('li',['item 3'])])


console.time('start');
patch(oldVnode,newVonde); //渲染頁面
console.timeEnd('start');

這里我們要實現一個patch方法,把Vnode渲染到頁面中

src/core/vdom/patch.js

import * as nodeOps from './node-ops'
import VNode from './vnode'


export default function patch(oldVnode,vnode){
 let isInitialPatch = false;
 if(sameVnode(oldVnode,vnode)){
 //如果兩個Vnode節點的根一致 開始diff
 patchVnode(oldVnode,vnode)
 }else{
 //這里就是不借助diff的實現
 const oldElm = oldVnode.elm;
 const parentElm = nodeOps.parentNode(oldElm);
 createElm(
 vnode,
 parentElm,
 nodeOps.nextSibling(oldElm)
 )
 if(parentElm != null){
 removeVnodes(parentElm,[oldVnode],0,0)
 }
 }
 return vnode.elm;
}
function patchVnode(oldVnode,vnode,removeOnly){
 if(oldVnode === vnode){
 return
 }
 const elm = vnode.elm = oldVnode.elm
 const oldCh = oldVnode.children;
 const ch = vnode.children

 if(isUndef(vnode.text)){
 //非文本節點
 if(isDef(oldCh) && isDef(ch)){
 //都有字節點
 if(oldCh !== ch){
 //更新children
 updateChildren(elm,oldCh,ch,removeOnly);
 }
 }else if(isDef(ch)){
 //新的有子節點,老的沒有
 if(isDef(oldVnode.text)){
 nodeOps.setTextContent(elm,'');
 }
 //添加子節點
 addVnodes(elm,null,ch,0,ch.length-1)
 }else if(isDef(oldCh)){
 //老的有子節點,新的沒有
 removeVnodes(elm,oldCh,0,oldCh.length-1)
 }else if(isDef(oldVnode.text)){
 //否則老的有文本內容 直接置空就行
 nodeOps.setTextContent(elm,'');
 }
 }else if(oldVnode.text !== vnode.text){
 //直接修改文本
 nodeOps.setTextContent(elm,vnode.text);
 }
}

function updateChildren(parentElm,oldCh,newCh,removeOnly){
 //這里認真讀下,沒什么難度的,不行的話 也可以搜索下圖文描述這段過程的

 let oldStartIdx = 0;
 let newStartIdx =0;
 let oldEndIdx = oldCh.length -1;
 let oldStartVnode = oldCh[0];
 let oldEndVnode = oldCh[oldEndIdx];
 let newEndIdx = newCh.length-1;
 let newStartVnode = newCh[0]
 let newEndVnode = newCh[newEndIdx]
 let refElm;
 const canMove = !removeOnly
 while(oldStartIdx <= oldEndIdx && newStartIdx <= newEndIdx){
 if(isUndef(oldStartVnode)){
 oldStartVnode = oldCh[++oldStartIdx]
 }else if(isUndef(oldEndVnode)){
 oldEndVnode = oldCh[--oldEndIdx]
 }else if(sameVnode(oldStartVnode,newStartVnode)){
 patchVnode(oldStartVnode,newStartVnode)
 oldStartVnode = oldCh[++oldStartIdx]
 newStartVnode = newCh[++newStartIdx]
 }else if(sameVnode(oldEndVnode,newEndVnode)){
 patchVnode(oldEndVnode,newEndVnode)
 oldEndVnode = oldCh[--oldEndIdx];
 newEndVnode = newCh[--newEndIdx];
 }else if(sameVnode(oldStartVnode,newEndVnode)){
 patchVnode(oldStartVnode,newEndVnode);
 //更換順序
 canMove && nodeOps.insertBefore(parentElm,oldStartVnode.elm,nodeOps.nextSibling(oldEndVnode.elm))
 oldStartVnode = oldCh[++oldStartIdx]
 newEndVnode = newCh[--newEndIdx]
 }else if(sameVnode(oldEndVnode,newStartVnode)){
 patchVnode(oldEndVnode,newStartVnode)
 canMove && nodeOps.insertBefore(parentElm,oldEndVnode.elm,oldStartVnode.elm)
 oldEndVnode = oldCh[--oldEndIdx]
 newStartVnode = newCh[++newStartIdx]
 }else{
 createElm(newStartVnode,parentElm,oldStartVnode.elm)
 newStartVnode = newCh[++newStartIdx];
 }
 }

 if(oldStartIdx > oldEndIdx){
 //老的提前相遇,添加新節點中沒有比較的節點
 refElm = isUndef(newCh[newEndIdx + 1]) ? null : newCh[newEndIdx+1].elm
 addVnodes(parentElm,refElm,newCh,newStartIdx,newEndIdx)
 }else{
 //新的提前相遇 刪除多余的節點
 removeVnodes(parentElm,oldCh,oldStartIdx,oldEndIdx)
 }
}
function removeVnodes(parentElm,vnodes,startIdx,endIdx){
 for(;startIdx<=endIdx;++startIdx){
 const ch = vnodes[startIdx];
 if(isDef(ch)){
 removeNode(ch.elm)
 }
 }
}

function addVnodes(parentElm,refElm,vnodes,startIdx,endIdx){
 for(;startIdx <=endIdx;++startIdx ){
 createElm(vnodes[startIdx],parentElm,refElm)
 }
}

function sameVnode(vnode1,vnode2){
 return vnode1.tag === vnode2.tag
}
function removeNode(el){
 const parent = nodeOps.parentNode(el)
 if(parent){
 nodeOps.removeChild(parent,el)
 }
}
function removeVnodes(parentElm,vnodes,startIdx,endIdx){
 for(;startIdx<=endIdx;++startIdx){
 const ch = vnodes[startIdx]
 if(isDef(ch)){
 removeNode(ch.elm)
 }
 }
}
function isDef (s){
 return s != null
}
function isUndef(s){
 return s == null
}
function createChildren(vnode,children){
 if(Array.isArray(children)){
 for(let i=0;i<children.length;i++){
 createElm(children[i],vnode.elm,null)
 }
 }
}
function createElm(vnode,parentElm,refElm){
 const children = vnode.children
 const tag = vnode.tag
 if(isDef(tag)){
 // 非文本節點
 vnode.elm = nodeOps.createElement(tag); // 其實可以初始化的時候就賦予
 createChildren(vnode,children);
 insert(parentElm,vnode.elm,refElm)
 }else{
 vnode.elm = nodeOps.createTextNode(vnode.text)
 insert(parentElm,vnode.elm,refElm)
 }
}
function insert(parent,elm,ref){
 if(parent){
 if(ref){
 nodeOps.insertBefore(parent,elm,ref)
 }else{
 nodeOps.appendChild(parent,elm)
 }
 }
}

這就是完整實現了

聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。TEL:177 7030 7066 E-MAIL:11247931@qq.com

文檔

深入理解Vue2.x的虛擬DOM diff原理

深入理解Vue2.x的虛擬DOM diff原理:前言 經常看到講解Vue2的虛擬Dom diff原理的,但很多都是在原代碼的基礎上添加些注釋等等,這里從0行代碼開始實現一個Vue2的虛擬DOM 實現VNode src/core/vdom/Vnode.js export class VNode{ constructor ( tag, //標簽名 c
推薦度:
標簽: 原理 VUE di
  • 熱門焦點

最新推薦

猜你喜歡

熱門推薦

專題
Top
主站蜘蛛池模板: 免费看欧美日韩一区二区三区 | 日韩综合区 | 欧美成人精品一区二区三区 | 青草青草伊人精品视频 | 在线视频 亚洲 | 亚洲综合日韩在线亚洲欧美专区 | 国产中文字幕在线 | 国产成人精品一区二三区在线观看 | 国产91久久久久久久免费 | 韩国理论三级在线观看视频 | 免费亚洲网站 | 日韩精品免费视频 | 亚洲欧美激情另类 | 美女一级毛片免费观看 | 久久精品无码一区二区日韩av | 精品国产三级a在线观看 | 欧美高清一区二区三 | 不卡二区 | 国产区第一页 | 欧美日a | 精品久久综合一区二区 | 日韩欧美亚洲国产高清在线 | 亚洲视频久久 | 精品国产一区二区三区久久久蜜臀 | 亚洲一区中文字幕 | 国产一区二区三区精品视频 | 国产精品www | 激情欧美一区二区三区中文字幕 | 爽妇网s| 日韩高清一区二区三区不卡 | 视频一区二区三区欧美日韩 | 美女一区 | 97成人资源 | 欧美一级色图 | 亚洲欧美日韩在线 | 精品视频一区二区 | 亚洲国产成人久久三区 | 国产片91 | 91视频久久 | 欧美一级专区免费大片 | 国产91精品黄网在线观看 |