You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Web Component中Tooltip的显示/隐藏、外部点击隐藏及单显实现

实现带交互逻辑的Tooltip Web Component

需求说明

  • 点击按钮切换Tooltip显示/隐藏(原逻辑已实现,优化了DOM选择可靠性)
  • 点击按钮或Tooltip以外的区域,自动隐藏所有Tooltip
  • 同一时间仅显示一个Tooltip,点击新按钮时自动关闭之前的

完整代码实现

JavaScript 代码

class BuildABox extends HTMLElement {
  constructor() {
    super();
    // 记录当前正在显示的Tooltip
    this.activeTooltip = null;
    // 绑定this指向,确保事件处理函数里能正确访问组件实例
    this.toggleTooltip = this.toggleTooltip.bind(this);
    this.handleOutsideClick = this.handleOutsideClick.bind(this);
    
    // 给所有带data-tooltip属性的按钮绑定点击事件
    this.querySelectorAll('[data-tooltip]').forEach(button => {
      button.addEventListener('click', this.toggleTooltip);
    });
    
    // 监听全局点击事件,处理外部点击隐藏逻辑
    document.addEventListener('click', this.handleOutsideClick);
  }

  toggleTooltip(e) {
    e.preventDefault();
    // 从当前点击的按钮里找到对应的Tooltip(比原有的lastChild.previousSibling更可靠)
    const tooltip = e.currentTarget.querySelector('.tooltip');
    if (!tooltip) return;

    // 如果当前Tooltip本来就是显示状态,直接隐藏
    if (this.activeTooltip === tooltip) {
      tooltip.classList.add('tw-invisible');
      this.activeTooltip = null;
      return;
    }

    // 先把之前显示的Tooltip关掉
    if (this.activeTooltip) {
      this.activeTooltip.classList.add('tw-invisible');
    }

    // 显示当前的Tooltip,更新激活状态记录
    tooltip.classList.remove('tw-invisible');
    this.activeTooltip = tooltip;
  }

  handleOutsideClick(e) {
    // 判断点击的地方是不是按钮或者Tooltip内部
    const isClickOnButton = e.target.closest('[data-tooltip]');
    const isClickOnTooltip = e.target.closest('.tooltip');
    // 如果都不是,且有激活的Tooltip,就隐藏它
    if (!isClickOnButton && !isClickOnTooltip && this.activeTooltip) {
      this.activeTooltip.classList.add('tw-invisible');
      this.activeTooltip = null;
    }
  }

  // 组件从DOM移除时,清理事件监听,避免内存泄漏
  disconnectedCallback() {
    document.removeEventListener('click', this.handleOutsideClick);
    this.querySelectorAll('[data-tooltip]').forEach(button => {
      button.removeEventListener('click', this.toggleTooltip);
    });
  }
}

customElements.define('build-a-box', BuildABox);

HTML 代码(优化重复ID问题)

注意:如果页面有多个Tooltip按钮,不能重复用id="tooltip",建议改成类名.tooltip,否则会导致DOM查询出错。修改后的HTML示例:

<button id="info-btn" aria-label="Information" type="button" data-info="{{ block.settings.product_description }}">
  <div data-tooltip="tooltip" class="tw-w-12">
    <svg xmlns="http://www.w3.org/2000/svg"
         viewBox="0 0 24 24"
         fill="currentColor"
         class="w-12 h-12"
    >
      <path fill-rule="evenodd" d="M2.25 12c0-5.385 4.365-9.75 9.75-9.75s9.75 4.365 9.75 9.75-4.365 9.75-9.75 9.75S2.25 17.385 2.25 12zm8.706-1.442c1.146-.573 2.437.463 2.126 1.706l-.709 2.836.042-.02a.75.75 0 01.67 1.34l-.04.022c-1.147.573-2.438-.463-2.127-1.706l.71-2.836-.042.02a.75.75 0 11-.671-1.34l.041-.022zM12 9a.75.75 0 100-1.5.75.75 0 000 1.5z" clip-rule="evenodd" />
    </svg>
    {% comment %} 这是要显示/隐藏的Tooltip {% endcomment %}
    <div class="tw-invisible z-50 tw-absolute tw-top-24 tw-max-w-[300px] tw-bg-blue-400 tw-text-white tw-border-graphite tw-border-2 tw-overflow-auto tw-rounded-2xl tw-p-4 tw-mt-1 tooltip">
      <p>{{ block.settings.product_description }}</p>
    </div>
  </div>
</button>

核心逻辑解释

  1. 单一Tooltip控制:用this.activeTooltip变量存当前显示的Tooltip,每次点击新按钮时,先关闭之前的,再打开当前的,确保同一时间只有一个Tooltip显示。
  2. 外部点击隐藏:监听整个文档的点击事件,用closest()方法判断点击位置是否在按钮或Tooltip范围内,不在就隐藏激活的Tooltip。
  3. 可靠的DOM选择:替换原有的lastChild.previousSibling为querySelector('.tooltip'),避免DOM结构里的空格、换行符导致的元素选择错误。
  4. 内存泄漏防护:在组件被移除时,移除所有绑定的事件监听,防止无用事件占用资源。

内容的提问来源于stack exchange,提问作者Mike Haslam

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 07:45:38