gem 的问题
执行顺序,父 -> 子(mounted 除外(使用 addMicrotaskToStack)),子 -> 父:
- parent constructor
- parent connectedCallback
- parent render
- child constructor
- child connectedCallback
- child render
- child mounted
- sibling...
- parent mounted
- ...
- parent updated
- chidren updated
- ...
- parent unmounted
- chidren unmounted
// 如何避免自定义元素属性被未来 HTML 标准属性冲突?
使用命名空间
// 不能在构造函数中设置 attribute // createElement 会报错,因为在未升级时将读不到
不能写全局样式(比如 ::selection ) // Chrome 支持,包括 ::target-text/::highlight 也支持
// 需要使用 adoptedStyle 应用共享样式;或者在 GemElement 上加静态属性 v2 不再继承
// DuoyunOptionsElement.adoptedStyleSheets 修改已存在组件样式
HTML 模版中的 style 元素不能覆盖 adoptedStyle 的样式
// 必须使用 important 或者 @layer(在 constructor stylesheet 中用)
不方便使用锚点定位
有一些非继承样式不能通过 inherit 应用到插槽中
// slot 也需要 inherit
自定元素 upgrade 时 constructor 中需要考虑已有 property // 例如 gem-route
不能树抖 // 元素定义都是副作用行为,手动按需导入
模版不能写动态标签
不能扩展自内置(a, dialog)元素 // 类型不知道写
attachShadow 选项 // 可以替代
state 的深度数据更改时并不一定能触发 UI 更新
// 整条数据链更新
// 扁平 state
// 所有组件绑定 state // 经过一些操作变成了 react 的更新方式
元素依赖不能很好的具备 IDE 支持 // 需要手动添加和删除依赖
元素名称更新不具备 IDE 支持 // 需要使用替换,受限于模版的写法
依赖运行时,一些计算(比如模版解析)造成不必要的性能消耗
没有冒泡的 "mouseover" 事件了 // 因为在一个元素内部
ParentNode.append 等方法操作已挂载的 gem 元素时,不会触发 unmounted, mounted 回调(会触发 disconnectCallback/connectCallback)
// 跨文档 append 时事件监听器还是能正常工作
ts 中用字段来标记的 attr 也会被当成 prop
// attr/prop 全部用 prop 的写法来写
用模版字符串手写 HTML 时(raw) attribute 的值必须写引号,不然值为空字符时解析不符合预期
同样具有 OOP 的问题:https://zhuanlan.zhihu.com/p/46207044
- 基类方法被覆盖 // 使用私有字段
- 方法 this 绑定 // 使用类字段
- 基类,子类方法调用凌乱
同一功能的代码写在不同的地方(生命周期中)// effect 方法类似 react effect hooks
effect 的依赖写法复杂(返回数组的函数)
lit-html 语法复杂:if 块、list
gem 元素内不要直接修改公开的 attr/prop(有可能造成更新死循环),但是 constructor,字段上可以这么做,当然 css state 往往需要内部修改
// gem 初始化 history 的 replace 将导致 electron webContents 崩溃
DOM 有 attr 和 prop 之分,attr 表示语义,prop 表示 js 对象属性,DOM 的有些 attr 和 prop 是同步的,有些不是
// string|boolean|number 类型的属性用 attr,否则使用 prop
为了统一开发体验,最佳实践是所有 attr 能像 prop 一样访问和设置。在 gem 中是在 constructor 中读取 observedAttributes 列表定义成访问器属性来实现的。问题:
- 并不是所有 attr 都能直接读取, 没有 observedAttributes 的 attr 只能 get/setAttribute
- attr 和 prop 名字重叠
- attr 要支持 lit-plugin 需要再写一份标记注释
- observed* 似乎有些多余, 没有写在 observedAttributes 中时直接访问得到的是 prop,且难以排查
- observedAttributes 合并原型链上的值
解决方案:使用装饰器。新问题:
- 装饰器字段通常都有默认值,但是 prop 装饰器没有 // 因为类型不确定
- v1 使用 TS 装饰器时不能使用 ES2022 私有字段 // 必须关闭 `useDefineForClassFields`
- 使用 ES 装饰器时必须插入文档才能正确读取属性 // 字段在插入文档时被隐式删除,类似
- 使用 ES 装饰器时在 DevTools 中修改元素的 Attribute 不会更新元素 // 使用 WebConsole 修改
// 除了 property,其他元素内部装饰器都将描述符转为烤串格式