xinglie / xinglie.github.io

blog
https://xinglie.github.io
153 stars 22 forks source link

基于编译的DOM属性处理 #75

Open xinglie opened 3 years ago

xinglie commented 3 years ago

property vs attribute

DOM 中它们在大部分情况下都相同或者能够同步,但某些节点不可以,比如<input type="checkbox"/>,初始时并未勾选,如果用户勾选后,我们无法通过setAttributeremoveAttribute把它变成未选中的状态,除非先setAttribute('checked','checked')然后再removeAttribute('checked'),如此一来比较麻烦,而且类似的属性不止checked一个,同时有类似属性的节点也不止input,我们需要面向未来有一个更通用的方案

数据驱动

目前到未来,使用数据驱动会是一个长久的方式,只需要用户准备好相应的数据,界面就需要保持与数据描述的一致,因此框架或方案应该处理好一切兼容问题,及面向未来可能新增、变化 的节点

运行时方案

目前大多数框架或方案会选择一个运行时处理,比如 https://github.com/patrick-steele-idem/morphdom/blob/master/src/specialElHandlers.js 穷举出所有需要特殊处理的节点,然后处理,该方案一会增加框架或类库的代码,二是如果后续有新增的节点需要处理,则需要更新类库,三是处理完属性(attribute)再处理(property)明显多处理了,应该是优先处理(property),再处理(attribute),不处理它们交叉的属性

编译时方案

magix-composer在编译模板时,对需要特殊处理的属性直接生成一个keyvalue的对象(因为有些属性attribute对应的property不一样,比如 class对应className 和 for 对应labelFor)

比如普通的节点

<div data-test="a" data-test1="b" class="selector"></div>

生成虚拟dom为

$createVNode('div', { 'data-test': 'a', 'data-test1': 'b', 'class': 'selector', })

需要特殊处理的节点

<input type="checkbox" data-test="a" class="b"/>

生成虚拟dom为

$createVNode('input', { 'type': 'checkbox', 'data-test': 'a', 'class': 'mp-_g_less_-b', 'checked': $nullCheck(checked)}, 1, { 'checked': 'checked', })

生成一份当前节点需要特殊处理的property清单。

在运行时,在处理attribute时,如果有对应的property则更新property,否则更新attribute。

在未来有新加需要处理的节点时,只需要更新编译器,加入相应的节点及它的property即可。这样对于运行时无须考虑当前是什么样的节点,某个属性该用attribute还是property更新。