gem 的问题

执行顺序,父 -> 子(mounted 除外(使用 addMicrotaskToStack)),子 -> 父:
  1. parent constructor
  2. parent connectedCallback
  3. parent render
  4. child constructor
  5. child connectedCallback
  6. child render
  7. child mounted
  8. sibling...
  9. parent mounted
  10. ...
  11. parent updated
  12. chidren updated
  13. ...
  14. parent unmounted
  15. 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,其他元素内部装饰器都将描述符转为烤串格式