纯JavaScript工具提示

34

我正在尝试使用纯 JavaScript 制作一个在 hover 时显示的工具提示。就像 Stack Overflow 上在悬停在个人资料名称上时会显示一个 div

我尝试使用 onmouseover, onmouseout 并添加了 setTimeout,以便让用户有几秒钟的时间将鼠标移动到工具提示内容上。但它并没有像我想象的那样工作。

我真的比使用任何库更喜欢纯 JavaScript。可以有人帮帮我吗?


这是我在纯 JavaScript 中所做的。

HTML

<div class = "name" onmouseover="show()" onmouseout="hide()">
    NAME
        <div class = "tooltip">
            PROFILE DETAILS
        </div>
    </div>

    <div class = "name" onmouseover="show()" onmouseout="hide()">
    NAME 2
        <div class = "tooltip" >
            PROFILE DETAILS 2
        </div>
    </div>

    <div class = "name" onmouseover="show()" onmouseout="hide()">
    NAME 3
        <div class = "tooltip" >
            PROFILE DETAILS 3
        </div>
    </div>

CSS

->

CSS

.name{
        float:left;
        margin:100px;
        border:1px solid black;
    }
    .tooltip{
        position:absolute;
        margin:5px;
        width:200px;
        height:100px;
        border:1px solid black;
        display:none;
    }

JavaScript

var name = document.getElementsByclassName("name");
    var tp = document.getElementsByclassName("tooltip");

    function show(){
        tp.style.display="block";
    }
    function hide(){
        tp.style.display="";
    }

3
为什么要使用 JavaScript?完全可以使用纯 CSS 解决问题。 - epascarello
请查看此链接:http://jqueryui.com/tooltip/ - Kathiravan
我需要在纯JS中使用过渡效果来使内容停留几秒钟,但这对于跨浏览器并不有帮助。 - Kishore
3
我不需要jQuery,我需要纯JavaScript。 - Kishore
@Kishore展示一下您做过而没有成功的事情。 - epascarello
显示剩余2条评论
7个回答

46

不需要JavaScript的解决方案

使用CSS伪类:hover设置隐藏元素的显示方式。需要将display:none添加到样式中,而不是直接在元素上使用,这样可以在:hover时覆盖它。

.couponcode:hover .coupontooltip {
  /* NEW */
  display: block;
}

.coupontooltip {
  display: none;
  /* NEW */
  background: #C8C8C8;
  margin-left: 28px;
  padding: 10px;
  position: absolute;
  z-index: 1000;
  width: 200px;
  height: 100px;
}

.couponcode {
  margin: 100px;
}
<div class="couponcode">First Link
  <span class="coupontooltip">Content 1</span>
  <!-- UPDATED -->
</div>

<div class="couponcode">Second Link
  <span class="coupontooltip"> Content 2</span>
  <!-- UPDATED -->
</div>

外部链接

跟进:

如果您需要支持非常旧的浏览器,您需要在鼠标进入div时向外部元素添加一个类,并在鼠标离开时删除该类。


编辑

您的代码没有工作,因为tp是一组元素,您正在将其视为一个元素。您需要做的是传递对元素的引用。

HTML:

<div class = "name" onmouseover="show(this)" onmouseout="hide(this)">  <!-- added "this" 2 times -->

**JavaScript:

//var name = document.getElementsByclassName("name");  /* not needed */
//    var tp = document.getElementsByclassName("tooltip"); /* not needed */


function show (elem) {  /* added argument */
    elem.style.display="block"; /* changed variable to argument */
}
function hide (elem) { /* added argument */
    elem.style.display="";  /* changed variable to argument */
}

如果我想使用 AJAX 在工具提示中获取数据库内容,这会有帮助吗? - Kishore
1
这是一个优雅的解决方案,我认为它应该得到更多的投票。这个小工具非常棒 +1 - khaverim
@MemetOlsen,我喜欢这个工具提示。有没有办法将工具提示移动到控件的右边缘?我知道它使用margin-left,但是有没有办法让它从输入框的最右边开始呢? - Rick
2
:hover>.coupontooltip 可以让你在任何元素内部放置工具提示。 - Brandon Henry

11
问题说:
纯JavaScript工具提示
但我认为在现代时代,我们可以使用原生JS和CSS。特别是当我们想要提供一个好看的样式时,这是必须的。
这个例子是纯JS和CSS的简单实现。
让我们使用CSS创建一个工具提示,并使用JS修改其行为。对于这个例子,我们将定义一个tip属性来存储将显示在工具提示上的文本。
visibility: hidden; 和 opacity: 0; 将保持.tooltip隐藏,并在[tip]:hover时显示出来。此外,我们还可以使用style.transform重新定位工具提示的发射点。

const elements = [...document.querySelectorAll('[tip]')]

for (const el of elements) {
  const tip = document.createElement('div')
  tip.classList.add('tooltip')
  tip.textContent = el.getAttribute('tip')
  const x = el.hasAttribute('tip-left') ? 'calc(-100% - 5px)' : '16px'
  const y = el.hasAttribute('tip-top') ? '-100%' : '0'
  tip.style.transform = `translate(${x}, ${y})`
  el.appendChild(tip)
  el.onpointermove = e => {
    if (e.target !== e.currentTarget) return

    const rect = tip.getBoundingClientRect()
    const rectWidth = rect.width + 16
    const vWidth = window.innerWidth - rectWidth
    const rectX = el.hasAttribute('tip-left') ? e.clientX - rectWidth : e.clientX + rectWidth
    const minX = el.hasAttribute('tip-left') ? 0 : rectX
    const maxX = el.hasAttribute('tip-left') ? vWidth : window.innerWidth
    const x = rectX < minX ? rectWidth : rectX > maxX ? vWidth : e.clientX
    tip.style.left = `${x}px`
    tip.style.top = `${e.clientY}px`
  }
}
[tip] .tooltip {
  position: fixed;
  font-size: 16px;
  line-height: 20px;
  padding: 5px;
  background: #444;
  border: 1px solid #222;
  visibility: hidden;
  opacity: 0;
  box-shadow: -2px 2px 5px rgba(0, 0, 0, 0.2);
  transition: opacity 0.3s, visibility 0s;
  color: white;
  min-width: 120px;
}

[tip]:hover .tooltip {
  visibility: visible;
  opacity: 1;
}

button {
  display: block;
  cursor: pointer;
  padding: 8px 15px;
  border: 1px solid gray;
  border-radius: 4px;
  margin: 50px 5px;
  width: 200px;
  font-size: 18px;
  background: white;
}

button:hover {
  border-color: dodgerblue;
}
<button tip="Click me here!">I have a tooltip</button>
<button tip="Click me aswell!" tip-top tip-left>Top-left tooltip</button>


7

对于非定制化的工具提示,您只需将要在工具提示中显示的消息添加到主

的title属性中即可。就像这样:

<div class = "name" onmouseover="show()" onmouseout="hide()" title="PROFILE DETAILS">

那么就不需要添加onmouseoveronmouseout事件处理程序。


6

原始代码的修复

我在寻找类似的内容时,发现了这个页面。它对我有所帮助,但我必须修复你的代码才能让它正常工作。我认为这就是你想做的。 你必须通过它们的“ID”引用你的对象。 这是我所做的,它可以正常工作:

function show(elem) {
  elem.style.display = "block";
}

function hide(elem) {
  elem.style.display = "";
}
.name {
  float: left;
  margin: 100px;
  border: 1px solid black;
}

.tooltip {
  position: absolute;
  margin: 5px;
  width: 200px;
  height: 50px;
  border: 1px solid black;
  display: none;
}
<div class="name" onmouseover="show(tooltip1)" onmouseout="hide(tooltip1)">
  NAME
  <div class="tooltip" id="tooltip1">
    PROFILE DETAILS
  </div>
</div>

<div class="name" onmouseover="show(tooltip2)" onmouseout="hide(tooltip2)">
  NAME 2
  <div class="tooltip" id="tooltip2">
    PROFILE DETAILS 2
  </div>
</div>

<div class="name" onmouseover="show(tooltip3)" onmouseout="hide(tooltip3)">
  NAME 3
  <div class="tooltip" id="tooltip3">
    PROFILE DETAILS 3
  </div>
</div>

External link


3
即使是$(document).ready,在纯JS中实现也很困难——请参见这里:$(document).ready equivalent without jQuery 因此,我使用了一个简单的版本:
window.addEventListener("load", function () {
    var couponcodes = document.getElementsByClassName("couponcode");
    for (var i = 0; i < couponcodes.length; i++) {
        couponcodes[i].addEventListener("mouseover", function () {
            var coupontooltip = this.getElementsByClassName("coupontooltip")[0];
            coupontooltip.removeAttribute("style");
        });
        couponcodes[i].addEventListener("mouseout", function () {
            var coupontooltip = this.getElementsByClassName("coupontooltip")[0];
            coupontooltip.style.display = "none";
        });
    }
});

http://jsfiddle.net/mynetx/5qbP3/


2

我在使用popper+tippy时遇到了一些延迟问题,开始寻找替代方案,并发现@Teocci的上面很好的答案

我需要进行以下调整,因此这是修改后的代码:

  • 将提示添加到body中,而不是由于css / innerHTML冲突而添加到el中
  • 使用js鼠标事件进行切换,防止嵌套触发
  • 箭头用于始终在底部使用情况
  • 能够清除所有先前的提示,以便在DOM更改时进行动态调用

CSS

.tooltip {
    position: fixed;
    z-index: 99;
    font-size: 12px;
    line-height: 12px;
    padding: 5px;
    background: #222;
    color: #fff;
    border: 1px solid #aaa;
    border-radius: 5px;
    font-family: sans-serif;
    box-sizing: border-box;
    /*box-shadow: -1px 2px 5px rgba(0, 0, 0, 0.2);*/
    transition: opacity 0.3s, visibility 0s;
    visibility: hidden;
    opacity: 0;
}

.tooltip-arrow{
    position: absolute;
    top: -4px;
    width: 7px;
    height: 7px;
    background: inherit;
    transform: rotate(45deg);
    border-top: 1px solid #aaa;
    border-left: 1px solid #aaa;
}

/* just for demo */
.box{
    margin: 25px;
    padding: 25px;
}

HTML

<div class="box" style="background:orange;" data-tip="hello i'm the parent">
    <div class="box" style="background:green;" data-tip="hi i'm the child"></div>
</div>

JS

function initTips(){
    // purge previous for dynamic render
    Array.from(document.querySelectorAll('.tooltip')).forEach(el => {
        el.remove()
    })

    // built upon: https://dev59.com/HWMl5IYBdhLWcg3we3Ho#69340293
    Array.from(document.querySelectorAll('[data-tip]')).forEach(el => {
        // tip
        let tip = document.createElement('div')
        tip.classList.add('tooltip')
        tip.innerText = el.getAttribute('data-tip')
        document.body.appendChild(tip)

        // arrow
        let arrow = document.createElement('div')
        arrow.classList.add('tooltip-arrow')
        tip.appendChild(arrow)

        // position tip + arrow once added
        setTimeout(() => {
            let elmPos = el.getBoundingClientRect()
            let tipPos = tip.getBoundingClientRect()
            tip.style.left = (elmPos.left + (elmPos.width - tipPos.width)/2) + 'px'
            tip.style.top = (elmPos.bottom + 5)+'px'
            arrow.style.left = (tipPos.width/2 - 5) + 'px'
        }, 0)

        // toggle with mouse
        el.onmouseover = e => {
            tip.style.opacity = 1
            tip.style.visibility = 'visible'
            e.stopPropagation() // stop parent
        };
         el.onmouseout = e => {
            tip.style.opacity = 0
            tip.style.visibility = 'hidden'
        };
    });
}

// kickoff
initTips()

// test calling again ie after dynamic content
setTimeout(initTips, 1000)

-1

document.addEventListener("mousemove",function awesome(e){
if(e.target.id != ""){
e.target.title = "#"+e.target.id;
}
}); 
<div id="dkf">random stuff</div>
<div id="dkls">some more random stuff</div>

而且你可以使用很多其他的东西来完成它,比如className、tagName等等...


如果要使用任何东西来托管工具提示的消息,请避免使用id、类名或标签名... 如果由于任何原因而被迫使用此解决方案,请考虑使用自定义“data”属性。 - Marcos Sandrini

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接