reecho
Version:
Reecho 是一款基于依赖收集的MVVM框架,它具有以下特点 - 声明式数据: 基于proxy的依赖收集 - 使用函数定义组件,但组件不会如React一样重复执行造成心智负担 - 读写分离,读取状态和更改状态统一使用函数,避免vue3的ref一样有时需要`xxx.value`有时不需要的不一致性 - 使用TS编写,类型友好
109 lines (101 loc) • 2.57 kB
text/typescript
import { isArray, isObject, isString } from "../shared";
// 需要当作 DOM Prop 处理的属性
const domPropsRE = /\[A-Z]|^(?:value|checked|selected|muted)$/;
export const patchProp = (
el: Element,
key: string,
preValue: any,
nextValue: any
): void => {
switch (key) {
case "class":
patchClass(el, nextValue);
break;
case "className":
patchClass(el, nextValue);
break;
case "style":
patchStyle(el, preValue, nextValue);
break;
default:
if (key[0] === "o" && key[1] === "n") {
// on开头视作事件
key = key.toLowerCase();
if (preValue) {
el.removeEventListener(key.slice(2), preValue);
}
if (nextValue) {
el.addEventListener(key.slice(2), nextValue);
}
} else if (domPropsRE.test(key)) {
el[key] = nextValue;
} else {
if (key !== "children") {
patchAttr(el, key, nextValue);
}
}
break;
}
};
function patchClass(el: Element, value: unknown) {
if (value === null) {
value = "";
} else if (isString(value)) {
value = "" + value;
} else if (isArray(value)) {
value = value.reduce((pre, current) => {
return pre + " " + current;
}, "");
} else if (isObject(value)) {
value = "";
for (let key in value as object) {
if (value[key]) {
value = value + " " + key;
}
}
}
el.className = String(value);
}
type Style = string | Record<string, string | string[]> | null;
function patchStyle(el: Element, pre: Style, next: Style) {
const style = (el as HTMLElement).style;
if (!next) {
el.removeAttribute("style");
} else if (isString(next)) {
if (pre !== next) {
style.cssText = next;
}
} else {
// style是对象或数组
for (const key in next) {
setStyle(style, key, next[key]);
}
if (pre && !isString(pre)) {
for (const key in pre) {
if (next[key] == null) {
// 把next中没有但prev中有的属性删除
setStyle(style, key, "");
}
}
}
}
}
function setStyle(
style: CSSStyleDeclaration,
name: string,
val: string | string[]
) {
if (isArray(val)) {
// 如果style是数组,递归添加到标签的style属性中
val.forEach((v) => setStyle(style, name, v));
} else {
style[name] = val;
}
}
function patchAttr(el: Element, key: string, value: any) {
if (value === null) {
el.removeAttribute(key);
} else if (value !== "props") {
el.setAttribute(key, value);
}
}