How to make this tooltip like this with pure javas

2019-02-26 01:48发布

问题:

I need to use JS no JQuery plugins to make a simple tooltip like on the image bellow.

Click on "?" image should open this tooltip and click again on the same image to close it. I think that it's simple for someone with good JS knowledge but I can't do it anyway :(

This is something that I have tried I know it's not too much but I am simply stuck.
How to display it like on the image, how to hide it when it;s open and how to add that little triangle in the corner?

myfiddle

<img id="info" src="http://www.craiglotter.co.za/wp-content/uploads/2009/12/craig_question_mark_icon1.png"/>
<div id="ttip">bla bla</div>

document.getElementById('info').addEventListener('click', function(){
    // how to check if it's visible so I can close tooltip
    document.getElementById('ttip').style.display="block";    
});

#info{margin-left:100px;margin-top:50px;}
#ttip
{
    width: 280px;
z-index: 15001;
top: 0px;
left: 0px;
display: none;
    border-color: #666;
background-color: #fff;
color: #666;
    position: relative;
border: 1px solid #666;
padding: 15px 9px 5px 9px;
text-align: left;
word-wrap: break-word;
overflow: hidden;
}

回答1:

Clean up the css and this will basically do it:

<script>
    function doTip(e){
          var elem = e.toElement;
          if(elem.getAttribute('data-tip-on')  === 'false') {

            elem.setAttribute('data-tip-on', 'true');
            var rect = elem.getBoundingClientRect();          
            var tipId = Math.random().toString(36).substring(7);
            elem.setAttribute('data-tip-id', tipId);
            var tip = document.createElement("div");
            tip.setAttribute('id', tipId);
            tip.innerHTML = elem.getAttribute('data-tip');
            tip.style.top = rect.bottom+ 10 + 'px';
            tip.style.left = (rect.left-200) + 'px';
            tip.setAttribute('class','tip-box');
            document.body.appendChild(tip);

          } else {

            elem.setAttribute('data-tip-on', 'false');
            var tip = document.getElementById(elem.getAttribute('data-tip-id'));
            tip.parentNode.removeChild(tip);


          }
    }
    function enableTips(){
        var elems = document.getElementsByClassName('quick-tip');
        for(var i = 0; i < elems.length; i++) { 
            elems[0].addEventListener("click", doTip, false);

        }
    }
    window.onload = function(){
        enableTips();
    }
</script>
<style>
    .quick-tip {
        background: black;
        color: #fff;
        padding: 5px;
        cursor: pointer;
        height: 15px;
        width: 15px;
        text-align: center;
        font-weight: 900;
        margin-left: 350px;

    }
    .tip-box {
    /* change dimensions to be whatever the background image is */
        height: 50px;
        width: 200px;
        background: grey;
        border: 1px solid black; 
        position: absolute;
    }
</style>


<div class="quick-tip" data-tip="THIS IS THE TIP! change elements 'data-tip' to change." data-tip-on="false">?</div>

<script>enableTips(); //might be required for jsfiddle, especially with reloads.</script>

Edit: fixed formatting and a bug. jsfiddle: http://jsfiddle.net/u93a3/



回答2:

Proof of concept:

The following markup in HTML: Create a div with class tooltip, add image and a div with class info with all text (can be multiple paragraphs if needed, scollbars is shown if necessary):

<div class='tooltip'>
  <img src='craig_question_mark_icon1.png' alt='Help'/>
  <div class='info'>
    Some text to fill the box with.
  </div>
</div>

The div.info is set to display:none in CSS.

When the page is loaded a pure javascript is running that draws an image of a triangle on a canvas-element, and then creates a div-element where the triangle is set as a background. Then, for every div.tooltip:

  1. add a click-eventhandler to the image
  2. replace the div.info with a div.info_container
  3. add a clone of the triangle-div to div.info_container
  4. add the original div.info to div.info_container

You can test it with this fiddle. It is tested successfully on FF25, Chrome31, IE10, Opera 12&18.

<!doctype html>
<html>
  <head>
    <script>
      "use strict";
      function click(event) {
        var elem = this.parentNode.querySelector('div.info_container');
        if (elem) elem.style.display = elem.style.display === 'block' ? 'none' : 'block';
      }
      function toolify() {
        var idx,
            len,
            elem,
            info,
            text,
            elements = document.querySelectorAll('div.tooltip'),
            canvas,
            imgurl,
            pointer,
            tipHeight = 20,
            tipWidth = 20,
            width = 200,
            height = 100,
            ctx;

        // Create a canvas element where the triangle will be drawn
        canvas = document.createElement('canvas');
        canvas.width = tipHeight;
        canvas.height = tipWidth;
        ctx = canvas.getContext('2d');

        ctx.strokeStyle = '#000';   // Border color
        ctx.fillStyle = '#fff';     // background color
        ctx.lineWidth = 1;

        ctx.translate(-0.5,-0.5);   // Move half pixel to make sharp lines
        ctx.beginPath();
        ctx.moveTo(1,canvas.height);              // lower left corner
        ctx.lineTo(canvas.width, 1);              // upper right corner
        ctx.lineTo(canvas.width,canvas.height);   // lower right corner
        ctx.fill();                               // fill the background
        ctx.stroke();                             // stroke it with border
        //fix bottom row
        ctx.fillRect(0,canvas.height-0.5,canvas.width-1,canvas.height+2);

        // Create a div element where the triangel will be set as background
        pointer = document.createElement('div');
        pointer.style.width = canvas.width + 'px';
        pointer.style.height = canvas.height + 'px';
        pointer.innerHTML = '&nbsp;' // non breaking space
        pointer.style.backgroundImage = 'url(' + canvas.toDataURL() + ')';
        pointer.style.position = 'absolute';
        pointer.style.top = '2px';
        pointer.style.right = '1px';
        pointer.style.zIndex = '1'; // place it over the other elements

        for (idx=0, len=elements.length; idx < len; ++idx) {
          elem = elements[idx];
          elem.querySelector('img').addEventListener('click',click);
          text = elem.querySelector('div.info');
          // Create a new div element, and place the text and pointer in it
          info = document.createElement('div');
          text.parentNode.replaceChild(info,text);
          info.className = 'info_container';
          info.appendChild(pointer.cloneNode());
          info.appendChild(text);
          //info.addEventListener('click',click);
        }
      }
      window.addEventListener('load',toolify);
    </script>
    <style>
      div.tooltip
      {
        position:relative;
        display:inline-block;
        width:300px;
        text-align:right;
      }
      div.tooltip > div.info
      {
        display:none;
      }
      div.tooltip div.info_container
      {
        position:absolute;
        right:20px;
        width:200px;
        height:100px;
        display:none;
      }
      div.tooltip div.info
      {
        text-align:left;
        position:absolute;
        left:1px;
        right:1px;
        top:20px;
        bottom:1px;
        color:#000;
        padding:5px;
        overflow:auto;
        border:1px solid #000;
      }
    </style>
  </head>
  <body>
    <div class='tooltip'>
      <img src='craig_question_mark_icon1.png' alt='Help'/>
      <div class='info'>
        Some text to fill the box with.
      </div>
    </div>
    <div class='tooltip'>
      <img src='craig_question_mark_icon1.png' alt='Help'/>
      <div class='info'>
        Some text to fill the box with.
        Some text to fill the box with.
        Some text to fill the box with.
        Some text to fill the box with.
      </div>
    </div>
  </body>
</html>