如何从包装在影子 DOM 中的另一个 Web 组件定位影子 DOM 中的元素

How to target an element inside a shadow DOM from another web component wrapped inside it

提问人:vitto 提问时间:9/23/2023 最后编辑:vitto 更新时间:9/23/2023 访问量:48

问:

好吧,我不确定我是否清楚问题标题......不好意思。

我想展示一个我已经在 DOM 上没有问题地使用:wc-tooltip

<div>
  You can use <span class="disk-space" id="help">20GB</span> of space.
  <wc-tooltip target="help">It works only if you are a vampire.</wc-tooltip>
</div>

我正在尝试在影子 DOM 的 Web 组件中使用它,但它不起作用:

<Host>
  <span><slot/></span>
  { this.tip && 
    <wc-icon id="help" name="my/fantastic/help/icon" />
    <wc-tooltip target="help">{ this.tip }</wc-tooltip>
  }
</Host>

这是因为我正在寻找 DOM 中的元素,而不是影子 DOM:

componentDidRender (): void {
  const caller = document.getElementById(this.target)
  if (caller) {
    this.caller = caller
    this.caller.addEventListener('mouseleave', this.handleVisibility.bind(this, false))
    this.caller.addEventListener('mouseenter', this.handleVisibility.bind(this, true))
    return
  }
  console.error('Warning: property target is undefined.')
}

哎呀,行不通。document.getElementById(this.target)

问题是我没有弄清楚如何解决这个问题,我可以使用替代属性来点阴影 DOM 元素,但如何?

元素 Web 组件 shadow-dom 模板 目标

评论

1赞 Danny '365CSI' Engelman 9/23/2023
您可以深入了解 shadowDOM:stackoverflow.com/questions/68937587/...
0赞 G. Tranter 9/23/2023
你需要分享完整的代码 - 根据你提供的内容,不可能理解你想做什么。你的组件的设计似乎是问题所在,但如果没有完整的代码,我无法确定。当你知道如何“潜入”影子 DOM 时,很容易“潜入”影子 DOM,但这可能不是一个正确的解决方案(如果你的组件设计得当,你通常永远不需要这样做)。
0赞 vitto 9/23/2023
谢谢@Danny'365CSI'Engelman,这就是我一直在寻找的。
0赞 vitto 9/23/2023
@G.Tranter 我正在尝试使用一个需要元素目标才能工作的 Web 组件,无论是在影子 DOM 外部还是内部,是保存影子 DOM 的组件包装器。我正在尝试制定一个可以同时工作的解决方案,也许具有不同的属性目标,例如 AND 或类似的东西。<Host>targetshadow-target

答:

1赞 G. Tranter 9/23/2023 #1

IMO 设计期望从组件外部访问其影子 DOM 内容的组件 - 除非通过公共 API (如 s) - 是不正确的设计。在这种情况下,我建议 wc-tooltip 应该在插槽中包含 wc-icon,而不是同级(或创建一个单独的组件来包含两者),并且还保留工具提示显示逻辑。实际可见的“工具提示”只是影子 DOM 的一部分,而不是整个组件,它实际上只是图标(或其他任何东西)的包装器,用于侦听鼠标活动以显示/隐藏可见的工具提示。所以像这样:@Method

<Host>
  <span><slot/></span>
  { this.tip && 
    <wc-tooltip>
      <wc-icon slot="trigger" id="help" name="my/fantastic/help/icon" />
      <div slot="tooltip">{ this.tip }</div>
    </wc-tooltip>
  }
</Host>

WC-工具提示:

@State() tooltipVisible: boolean = false;

@Listen('mouseenter') showTootlip() {
  this.tooltipVisible = true;
}

@Listen('mouseleave') hideTooltip() {
  this.tooltipVisible = false;
}

render() {
  return <Host>
    <slot name="trigger" />
    <div style={{ 
      display: this.tooltipVisible ? 'block' : 'none', 
      position: 'absolute', 
      left: ... 
    }}>
      <slot name="tooltip" />
    </div>
  </Host>;
}

评论

1赞 vitto 9/23/2023
谢谢你的建议,你给了我一些关于如何处理它的新视角。