1: h 函数:
<body>
<button>点击我改变DOM</button>
<div id="container"></div>
</body>
1: 创建patch 函数
const patch = init([classModule, propsModule, styleModule, eventListenersModule]);
const vnode1 = h('ul', {}, [
h('li', {}, 'A'),
h('li', {}, 'B'),
h('li', {}, 'C'),
h('li', {}, 'D')
])
const vnode2 = h('ul', {}, [
h('li', { key: 'A' }, 'A'),
h('li', { key: 'B' }, 'B'),
h('li', { key: 'C' }, 'C'),
h('li', { key: 'D' }, 'D'),
h('li', { key: 'E' }, 'E')
])
const container = docuent.getElementById('container'); // 获取元素节点
const btn= docuent.getElementById('button'); // 获取元素节点
patch(container, vnode1); // 需要渲染的容器, 需要渲染的vnode 节点
// 点击按钮事件, 点击事件时, 将vnode1 改变为vnode2; 内部最小量更新
btn.onclick = function() {
patch(vnode1, vnode2)
}
diff 算法中的patch函数是 重要的函数, 实现最小量更新;
v-for: 一定要加key 值, 否则就会全量更新。 key: 是唯一标识,算法效率会非常高效。
key: 就是实现最小量更新的, 提高算法效率。 (当然: key 很重要。key是这个节点的唯一标识, 告诉 diff算法, 在更改前后他们是同一DOM 节点)。
只会进行同层比较, 不会进行跨层比较。 即使是同一片虚拟节点, 但是跨层了, 精细化比较不会diff你。 而是暴力拆除旧的, 然后插入新的。 只要是父级节点改变, 所有的子级
只会进行同层比较, 不会进行跨层比较。
// 什么是同一个虚拟节点? 同一个虚拟节点 (就是选择器相同, 并且key值相同)
diff 算法是同层比较效率最高: patch 函数;
分析 diff 算法:
patch 函数被调用: 判断vnode 是虚拟节点还是DOM 节点? 如果是DOM节点 将oldnode 包装为虚拟节点;
如果是虚拟节点 (oldnode 和 newnode 是不是同一个节点??) ===> 如果不是暴力删除旧的, 插入新的
===> 然后进行精细化比较。
如何判断新 旧DOM 为同一个节点: 就是有相同的选择器, 和相同的key值
sameVnode() 函数:
function sameVnode (vnode1: VNode, vnode2: VNode): boolean {
return vnode1.key === vnode2.key && vnode1.sel === vnode2.sel
}
创建一个patch.js 文件夹
patch 函数
// 函数的功能非常简单, 就是把传入的5个参数组合成对象返回
let vnode (sel, data, children, text, elm) {
return { sel, data, children, text, elm };
}
export default vnode;
--------------------------------------------------------------
创建元素节点 创建 createElement.js 文件
export default function(vnode, pivot) {
console.log('目的就是虚拟节点', vonode, '插入到标杆', pivot, '前');
创建一个DOM 节点, 这个节点是单一节点
let domNode = document.createElement(vnode.sel);
有子节点还是有文本??
if(vnode.text != "" && (vnode.children == undefined || vnode.children.length ==0)) {
// 它内部是文本
domNode.innerText = vnode.text;
// 将单一节点上树, 让标杆节点的父元素调用insertBefore 方法, 将新的单一节点插入到标签节点之前
pivot.parentNode.insertBefore(domNode, pivot);
}else if(Array.isArray(vnode.children) && vnode.children.length > 0) {
//创建子节点
}
}
import vnode form './vnode.js' // 导入vnode 虚拟节点
const patch (oldVnode, newVnode) {
// 判断传入的第一个参数, 是DOM 节点还是虚拟DOM 节点?
if(oldVnode.sel == '' || oldVnode.sel == undefined) {
// 说明传入的第一个参数是DOM 节点, 此时要包装为虚拟节点
oldVnode = vnode(oldVnode.tagName.toLowerCase(), {}, [], underfined, oldVnode);
}
// oldVnode 和 newVnode 是不是同一个节点
if(oldVnode.key == newVnode.key && oldVnode.sel == newVnode.sel) {
'是同一个节点' ===> 进行精细化比较
} else {
'不是同一个节点, 暴力插入新的, 删除旧的'
}
}
export default patch; // 向外暴露patch 函数