如何观察 ShadowDOM v1 插槽上的分布变化?



(这不是我们如何观察 v0 shadow 根上的分布变化?的副本,因为这个问题是针对 ShadowDOM v0 的,并且它提到的关于 ShadowDOM v1 的插槽和插槽更改事件是不完整的)

问题是,slotchange事件告诉您节点或元素何时通过插槽分发,但它不一定告诉您节点或元素的最终分布。如果您将插槽分配给分配给插槽的插槽(因此您有一个由三个 ShadowRoot 树组成的层次结构),则由于事件冒泡,将在所有三个插槽上触发一个slotchange事件,并且气泡顺序将从祖先插槽到最后代插槽,这意味着最深的插槽将是最后一个触发事件。如果使用事件capture阶段,则顺序相反。在事件传播期间,event.target将始终是最祖先的影子树的槽,这意味着event.target不是节点或元素最终分配到的槽。

问题:不是很明显的是,我们如何使用 slotchange 事件检测节点或元素的最终分布(因为没有其他事件像假设的distribution事件那样简单而有用)?

我们没有的是像distributionchange这样的单个非冒泡事件,当且仅当节点或元素最终分发(或未分发)到(或从)该插槽时,它会在插槽上触发。我们也没有像slot.distributedNodes()slot.distributedElements()这样的方法,可以假设在我们的非冒泡distributionchange事件处理程序中告诉我们这些信息。

虽然不像与distributedNodesdistributeElementsAPI 配对的distributionchange事件那样立即明显,但一旦了解了与slotchangedistributedNodedistributeElements相关的一些细节,答案实际上相当简单:

someSlot.addEventListener('slotchange', event => {
// Always use `event.currentTarget` because that points to the slot
// that this event handler is on, whereas `event.target` will
// always point to the slot from the ancestor-most shadow tree.
// That ancestor-most tree's slot is slotted to this slot (currentTarget)
// or to some other slot that is ultimately distributed to this slot.
const slot = event.currentTarget
// If the slot has an assignedSlot, then it can not possibly be the slot
// where nodes or elements are finally distributed to, so return an empty
// array in that case. Otherwise, the slot must be the final distribution
// slot, in which case calling assignedNodes with flatten:true will give
// the desired result (the finally-distributed nodes).
const distributedNodes = slot.assignedSlot ? [] : slot.assignedNodes({flatten: true})
// Similar if you just want elements (f.e. not text nodes):
const distributedElements = slot.assignedSlot ? [] : slot.assignedElements({flatten: true})
})

如果你有树层次结构document > shadowtree1 > shadowtree2 > shadowtree3,其中shadowtree1有一个插槽A被槽(分配)到shadowtree2中的槽B,其中槽B槽到shadowtree3中的槽C,那么如果document中的元素foobarbaz被槽到槽A, 如果您在这三个插槽中的每一个上都有此事件处理程序,则每个插槽的distributedElements结果将是:

  • 答:[]
  • 乙: []
  • C: [foo, bar, baz]

如果我们没有检查assignedSlot并且只使用assignedElements({flatten: true}),结果将是以下内容,它不会告诉我们哪个插槽实际上代表元素分布到的位置:

  • 答:[福,酒吧,巴兹]
  • 乙: [福, 酒吧, 巴兹]
  • C: [foo, bar, baz]

因为这样我们就不知道哪个插槽实际上是元素分布到的插槽。

如果要从shadowtree3中删除插槽C,则事件将再次触发,结果将是:

  • 答:[]
  • 乙: [福, 酒吧, 巴兹]

利用这些知识,我们可以为distributionchangedistributedElements()API 制作填充物......

最新更新