JavaScript tooltip 位置限制在特定 div 内 - 优化代码实现

本文将提供 JavaScript 代码优化方案,将 tooltip 的显示区域限制在指定的 div 元素内部,避免超出范围。

原代码:

let selectedLabel = null;
let currentTooltip = null;
let tooltipTimer = null;

labels.forEach((label) => {
  label.addEventListener("mouseover", (e) => {
    if (currentTooltip) {
      document.querySelector(".category-options-wrapper").removeChild(currentTooltip);
      clearTimeout(tooltipTimer);
    }

    const tooltip = document.createElement("div");
    tooltip.classList.add("tooltip");
    tooltip.innerHTML = label.getAttribute("data-title");
    const imgSrc = label.getAttribute("data-img");
    if (imgSrc) {
      const img = new Image();
      img.src = imgSrc;
      img.onload = function() {
        tooltip.appendChild(document.createElement('br'));
        tooltip.appendChild(img);
      }
      img.onerror = function() {
        console.log("Error: Failed to load image '" + imgSrc + "'");
        left = e.pageX + 10;
        top = e.pageY + 10;
        tooltip.style.left = left + "px";
        tooltip.style.top = top + "px";
      }
    }
    tooltip.style.maxWidth = "300px";
    document.querySelector(".category-options-wrapper").appendChild(tooltip);

    const tooltipWidth = tooltip.offsetWidth;
    const tooltipHeight = tooltip.offsetHeight;
    const mouseX = e.clientX;
    const mouseY = e.clientY;
    const wrapperRect = document.querySelector(".category-options-wrapper").getBoundingClientRect();

    let left = mouseX - wrapperRect.left + 10;
    let top = mouseY - wrapperRect.top + 10;

    if (!imgSrc) {
      left = e.pageX + 10;
      top = e.pageY + 10;
    } else if (left + tooltipWidth > wrapperRect.left + wrapperRect.width) {
      // tooltip 超出右侧边界
      left = wrapperRect.left + wrapperRect.width - tooltipWidth;
    }

    if (top + tooltipHeight > wrapperRect.top + wrapperRect.height) {
      // tooltip 超出下方边界
      top = wrapperRect.top + wrapperRect.height - tooltipHeight;
    }

    tooltip.style.left = left + "px";
    tooltip.style.top = top + "px";

    tooltip.addEventListener("mousemove", () => {
      clearTimeout(tooltipTimer);
    });

    tooltip.addEventListener("mouseout", () => {
      tooltipTimer = setTimeout(() => {
        document.querySelector(".category-options-wrapper").removeChild(tooltip);
        currentTooltip = null;
        // 如果该 label 元素是当前选中的元素,则不还原其背景颜色
        if (label == selectedLabel) {
          label.style.backgroundColor = "";
        }
      }, 5000);
    });

    currentTooltip = tooltip;
    // 如果当前已有选中的 label 元素,则将其背景颜色还原
    if (selectedLabel && label !== selectedLabel) {
      selectedLabel.style.backgroundColor = "";
    }
    // 将当前 label 元素设置为选中,并将其背景颜色设置为 '#40b40d'
    selectedLabel = label;
    selectedLabel.style.backgroundColor = "rgba(64, 180, 13, 0.6)";
  });

  label.addEventListener("mouseleave", () => {
    if (currentTooltip) {
      tooltipTimer = setTimeout(() => {
        document.querySelector(".category-options-wrapper").removeChild(currentTooltip);
        currentTooltip = null;
        // 如果该 label 元素是当前选中的元素,则不还原其背景颜色
        if (label == selectedLabel) {
          label.style.backgroundColor = "";
        }
      }, 2000);
    }
  });
});

优化后的代码:

const optionsRect = document.querySelector(".options").getBoundingClientRect();

// ...

let left = mouseX - optionsRect.left + 10;
let top = mouseY - optionsRect.top + 10;

if (!imgSrc) {
  left = e.pageX + 10;
  top = e.pageY + 10;
} else {
  if (left + tooltipWidth > optionsRect.left + optionsRect.width) {
    // tooltip 超出右侧边界
    left = optionsRect.left + optionsRect.width - tooltipWidth;
  }

  if (top + tooltipHeight > optionsRect.top + optionsRect.height) {
    // tooltip 超出下方边界
    top = optionsRect.top + optionsRect.height - tooltipHeight;
  }
}

// ...

currentTooltip = tooltip;

// ...

label.addEventListener("mouseleave", () => {
  if (currentTooltip) {
    tooltipTimer = setTimeout(() => {
      document.querySelector(".options").removeChild(currentTooltip);
      currentTooltip = null;
      // 如果该 label 元素是当前选中的元素,则不还原其背景颜色
      if (label == selectedLabel) {
        label.style.backgroundColor = "";
      }
    }, 2000);
  }
});

代码修改说明:

  1. 获取 optionsRect 的方式:

    • 原代码使用 document.querySelector(".category-options-wrapper").getBoundingClientRect(); 获取 category-options-wrapper 元素的边界矩形。
    • 修改后使用 document.querySelector(".options").getBoundingClientRect(); 获取 options 元素的边界矩形。
  2. 计算 tooltip 位置的方式:

    • 原代码使用 wrapperRect 计算 tooltip 的位置。
    • 修改后使用 optionsRect 计算 tooltip 的位置。
  3. mouseleave 事件中移除 tooltip 的父元素:

    • 原代码使用 document.querySelector(".category-options-wrapper").removeChild(currentTooltip); 移除 tooltip 元素。
    • 修改后使用 document.querySelector(".options").removeChild(currentTooltip); 移除 tooltip 元素。

总结:

通过以上修改,代码将 tooltip 的显示区域限制在 options 元素内部,避免超出范围。修改后的代码更符合实际需求,并提供了更加精确的 tooltip 位置控制。

建议:

  • 可以考虑使用 CSS 样式来控制 tooltip 的显示范围,例如设置 overflow: hidden 属性。
  • 可以使用 JavaScript 库来简化 tooltip 的实现,例如 popper.js
  • 可以根据实际需求调整 tooltip 的位置和显示方式。
JavaScript tooltip 位置限制在特定 div 内 - 优化代码实现

原文地址: https://www.cveoy.top/t/topic/ofJC 著作权归作者所有。请勿转载和采集!

免费AI点我,无需注册和登录