(这不是我们如何观察 v0 shadow 根上的分布变化?的副本,因为这个问题是针对 ShadowDOM v0 的,并且它提到的关于 ShadowDOM v1 的插槽和插槽更改事件是不完整的)
问题是,slotchange
事件告诉您节点或元素何时通过插槽分发,但它不一定告诉您节点或元素的最终分布。如果您将插槽分配给分配给插槽的插槽(因此您有一个由三个 ShadowRoot 树组成的层次结构),则由于事件冒泡,将在所有三个插槽上触发一个slotchange
事件,并且气泡顺序将从祖先插槽到最后代插槽,这意味着最深的插槽将是最后一个触发事件。如果使用事件capture
阶段,则顺序相反。在事件传播期间,event.target
将始终是最祖先的影子树的槽,这意味着event.target
不是节点或元素最终分配到的槽。
问题:不是很明显的是,我们如何使用 slotchange 事件检测节点或元素的最终分布(因为没有其他事件像假设的distribution
事件那样简单而有用)?
我们没有的是像distributionchange
这样的单个非冒泡事件,当且仅当节点或元素最终分发(或未分发)到(或从)该插槽时,它会在插槽上触发。我们也没有像slot.distributedNodes()
或slot.distributedElements()
这样的方法,可以假设在我们的非冒泡distributionchange
事件处理程序中告诉我们这些信息。
虽然不像与distributedNodes
或distributeElements
API 配对的distributionchange
事件那样立即明显,但一旦了解了与slotchange
和distributedNode
或distributeElements
相关的一些细节,答案实际上相当简单:
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
中的元素foo
、bar
和baz
被槽到槽A
, 如果您在这三个插槽中的每一个上都有此事件处理程序,则每个插槽的distributedElements
结果将是:
- 答:[]
- 乙: []
- C: [foo, bar, baz]
如果我们没有检查assignedSlot
并且只使用assignedElements({flatten: true})
,结果将是以下内容,它不会告诉我们哪个插槽实际上代表元素分布到的位置:
- 答:[福,酒吧,巴兹]
- 乙: [福, 酒吧, 巴兹]
- C: [foo, bar, baz]
因为这样我们就不知道哪个插槽实际上是元素分布到的插槽。
如果要从shadowtree3
中删除插槽C
,则事件将再次触发,结果将是:
- 答:[]
- 乙: [福, 酒吧, 巴兹]
利用这些知识,我们可以为distributionchange
和distributedElements()
API 制作填充物......