来个案例
/*
* @Author: Lin zefan
* @Date: 2022-03-21 21:46:14
* @LastEditTime: 2022-04-02 15:41:35
* @LastEditors: Lin zefan
* @Description:
* @FilePath: windowmini-vue3windowexamplewindowupdateComponentwindowApp.js
*
*/
import { h, ref } from "../../lib/mini-vue.esm.js";
export default {
setup() {
const counter = ref(1);
function inc() {
counter.value += 1;
}
const props = ref({
foo: "foo",
bar: "bar",
});
function patchProp1() {
// 逻辑1: old !== new
props.value.foo = "new-foo";
}
function patchProp2() {
// 逻辑2: new === undefined || null, remove new
props.value.bar = undefined;
}
function patchProp3() {
// 逻辑3: old 存在,new 不存在,remove new
props.value = {
car: "car",
};
}
return {
counter,
props,
inc,
patchProp1,
patchProp2,
patchProp3,
};
},
render() {
return h(
"div",
{
foo: this.props.foo,
bar: this.props.bar,
car: this.props.car,
},
[
h("div", {}, "" + this.counter),
h("button", { onClick: this.inc }, "inc"),
h("button", { onClick: this.patchProp1 }, "修改props"),
h("button", { onClick: this.patchProp2 }, "删除props"),
h("button", { onClick: this.patchProp3 }, "props重新赋值"),
]
);
},
};
实现
更新props
更新props时候主要考虑2种情况
- 更新
- 删除
render.ts
function updateElement(n1, n2, container, parentComponent) {
// 更新props
patchProps(n1, n2);
}
function patchProps(n1: any, n2: any) {
const prevProps = n1.props || EMPTY_OBJECT;
const nowProps = n2.props || EMPTY_OBJECT;
// 相等不操作
if (prevProps === nowProps) return;
// dom元素取的是旧vnode,覆盖新vnode的el
const el = (n2.el = n1.el);
// 值新增、变更的情况
for (const key in nowProps) {
if (prevProps[key] !== nowProps[key]) {
hostPatchProp(el, key, nowProps);
}
}
// 旧的props为空,不遍历
if (EMPTY_OBJECT === prevProps) return;
// 键不存在删除
for (const key in prevProps) {
if (!(key in nowProps)) {
hostPatchProp(el, key, null);
}
}
}
runtime-dom/index.ts
export function patchProp(el, key, props) {
const val = (props && props[key]) || null;
/** 注册事件
* 1. 判断是否on开头并包含一个大写字母开头
* 2. 是的话,截取on后面的内容
* 3. 注册元素事件
*/
if (isEvents(key)) {
el.addEventListener(isEvents(key), val);
} else {
// 如果当前的值是空的,那要把对应的行内属性删除
if (val === undefined || val === null) {
el.removeAttribute(key);
return;
}
el.setAttribute(key, val);
}
}