Как указать место для вывода hint в HTML?

125
03 мая 2021, 16:20

В HTML странице есть две таблицы (Т1 и Т2) одна над другой. Каждая ячейка содержит ссылку и скрытый текст для вывода. т.е. нажимая на ячейку, над таблицей выводится текст, который соответствует этой ячейке. В данный момент скрипт написан так, что независимо от того, в какой таблице кликаем по ячейке информация всегда появляется над первой таблицей, а надо чтобы информация выводилась над той таблицей в которой кликаем по ячейке.

Содержание таблицы 1 (пример):

<div id="hint" onClick="this.style.display='none'"></div>
<table>
  <tr>
    <td>
       <span data-hint="Связь 11 - 11" onClick="hint(this,event)">t1_11_11</span> 
    </td>
    <td>
       <span data-hint="Связь 5 - 7" onClick="hint(this,event)">t1_5_7b</span> 
    </td>
  </tr>
</table>

Содержание таблицы 2 (пример):

<table>
  <tr>
    <td>
       <span data-hint="Связь 3 - 15" onClick="hint(this,event)">t2_3_15</span> 
    </td>
    <td>
       <span data-hint="Связь 2 - 8" onClick="hint(this,event)">t2_2_8b</span> 
    </td>
  </tr>
</table>

Скрипт выглядит так:

        <script>
            function hint(obj,event) {
              h = document.getElementById('hint'); 
              h.innerHTML = obj.dataset.hint; 
              h.style.left = event.pageX; 
              h.style.top = event.pageY+10; 
              h.style.display = 'block'; 
            } 
        </script>;

Что и где надо добавить, чтобы результаты выводились над разными ячейками?

Answer 1

Я предлагаю завязаться через абсолютную адресацию. Т.е. получить позицию относительно вернего левого угла, и от неё всё описать. Например так

h = document.getElementById('hint'); 
h.style.position= "absolute";
h.style.display = "block";
h.style.top=(getOffset(event.target||event.srcElement).top-1)+"px"; 
h.style.left=(getOffset(event.target||event.srcElement).left-2)+"px"; 

Где 1 и 2 - подберете константы.

Ф-ция

function getOffset(elem) {
    if (elem.getBoundingClientRect) {
    var box = elem.getBoundingClientRect();
    var body = document.body;
    var docElem = document.documentElement;
    var scrollTop = window.pageYOffset || docElem.scrollTop || body.scrollTop;
    var scrollLeft = window.pageXOffset || docElem.scrollLeft || body.scrollLeft;
    var clientTop = docElem.clientTop || body.clientTop || 0;
    var clientLeft = docElem.clientLeft || body.clientLeft || 0;
    return { top: Math.round(box.top +  scrollTop - clientTop), left: Math.round(box.left + scrollLeft - clientLeft) }      
    } else {
         var top=0, left=0
    while(elem) {
        top = top + parseFloat(elem.offsetTop);
        left = left + parseFloat(elem.offsetLeft);
        elem = elem.offsetParent ;
       }
       return {top: top, left: left};
       }
}

Ф-ция позицировния getOffset

Так же рекомендую посмотреть этот пример Всплывающие подсказки с data-hint

Answer 2

оставлю тут для будущих пользователей, у которых возникнет подобный вопрос, просто ещё один вариант реализации подсказок (простой, без проверки на видимость).

codepen

class Hint { 
  constructor(node) { 
    this.node = node; 
 
    if (!this.node) return; 
 
    this.onHover = this.onHover.bind(this); 
    this.onLeave = this.onLeave.bind(this); 
 
    this.node.addEventListener('mouseenter', this.onHover, false); 
    this.node.addEventListener('mouseleave', this.onLeave, false); 
  } 
 
  onHover() { 
    const text = this.getText(); 
    const type = this.getType(); 
 
    this._createHint(text, type); 
  } 
 
  onLeave() { 
    document.querySelector('.hint').remove(); 
  } 
 
  getText() { 
    return this.node.getAttribute('data-hint'); 
  } 
 
  getType() { 
    return this.node.getAttribute('data-type'); 
  } 
 
  _createHint(text, type) { 
    const content = ` 
      <div class="hint__container"> 
        <div class="hint__text">${text}</div> 
      </div> 
    ` 
 
    const hintWnd = this._createWindow(type); 
 
    hintWnd.innerHTML = content; 
 
    this.node.appendChild(hintWnd); 
  } 
 
  _createWindow(type) { 
    const typeClass = this._getTypeClass(type); 
 
    const hintNode = document.createElement('div'); 
 
    hintNode.classList.add('hint', typeClass); 
 
    return hintNode; 
  } 
 
  _getTypeClass(type) { 
    // created for relief html, can be delete 
    switch (type) { 
      case 'important': 
        return 'hint_type_important'; 
        break; 
      default: 
        return 'hint_type_default'; 
    } 
  } 
} 
 
[...document.querySelectorAll('[data-widget="hint"]')] 
.forEach(hint => new Hint(hint));
* { 
  margin: 0; 
  padding: 0; 
  box-sizing: border-box; 
} 
 
body { 
  font-family: "Roboto", sans-serif; 
  display: flex; 
  align-items: center; 
  justify-content: center; 
  height: 100vh; 
} 
 
.block { 
  max-width: 500px; 
  width: 100%; 
} 
 
.block__container { 
  display: flex; 
  flex-wrap: wrap; 
  margin: -15px; 
} 
 
.block__item { 
  padding: 15px; 
  width: 33.333333333%; 
  height: 176.66px; 
} 
 
.block__content { 
  height: 100%; 
  width: 100%; 
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12), 0 1px 2px rgba(0, 0, 0, 0.24); 
  border-radius: 10px; 
  cursor: pointer; 
  transition: all 0.3s cubic-bezier(.25, .8, .25, 1); 
  position: relative; 
} 
 
.block__content:hover, 
.block__content:focus { 
  box-shadow: 0 14px 28px rgba(0, 0, 0, 0.25), 0 10px 10px rgba(0, 0, 0, 0.22); 
} 
 
.hint { 
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12), 0 1px 2px rgba(0, 0, 0, 0.24); 
  padding: 10px 20px; 
  border-radius: 5px; 
  position: absolute; 
  z-index: 2; 
  background: #fff; 
  animation: scaled .3s forwards; 
  top: -50px; 
  left: 20px; 
} 
 
.hint_type_important { 
  color: #FF6F61; 
} 
 
.hint_type_default { 
  color: #838383; 
} 
 
@keyframes scaled { 
  from { 
    transform: scale(0.1); 
  } 
  to { 
    transform: scale(1); 
  } 
}
<div class="block"> 
  <div class="block__container"> 
    <div class="block__item"> 
      <div class="block__content" data-widget="hint" data-hint="Hint #1" data-type="important"></div> 
    </div> 
 
    <div class="block__item"> 
      <div class="block__content" data-widget="hint" data-hint="Hint #2"></div> 
    </div> 
 
    <div class="block__item"> 
      <div class="block__content" data-widget="hint" data-hint="Hint #3"></div> 
    </div> 
 
    <div class="block__item"> 
      <div class="block__content" data-widget="hint" data-hint="Hint #4"></div> 
    </div> 
 
    <div class="block__item"> 
      <div class="block__content" data-widget="hint" data-hint="Hint #5"></div> 
    </div> 
 
    <div class="block__item"> 
      <div class="block__content" data-widget="hint" data-hint="Hint #6"></div> 
    </div> 
  </div> 
</div>

READ ALSO
Передать данные из js в django

Передать данные из js в django

Как передать из django в html я понял, нужно в viewspy в context добавить то, что хотим передать

91
Как сверстать блоки табами по 3

Как сверстать блоки табами по 3

В десктопной версии это выглядит вот так http://prntscrcom/om0l1m А для мобильной версии нужно вот так http://prntscr

102
JavaScript Помогите оптимизировать код

JavaScript Помогите оптимизировать код

Помогите оптимизировать создание таблицы с результатами, перебирая содержимое объектов

117