В веб-компоненте Как показать всплывающую подсказку и скрыть всплывающую подсказку при нажатии снаружи или при нажатии другой всплывающей подсказки

У меня есть этот веб-компонент, в котором есть карточки с всплывающими подсказками.

Я пытаюсь выполнить 3 вещи. Я пытаюсь использовать Vanilla Javascript против jQuery или других библиотек.

  1. Показать, когда кнопка нажата, и скрыть, если кнопка нажата снова. В настоящее время это работает.

  2. Скрыть при нажатии за пределами кнопки. Я попытался выбрать документ, а затем сравнить щелкнутый элемент с элементом, на который я хочу настроить таргетинг, но у меня возникли проблемы с таргетингом.

  3. Показывать только 1 всплывающую подсказку за раз, поэтому, если 1 открыта, вы нажимаете другую, отображается только вторая. Не уверен, как подойти к этому.

Вот что у меня есть до сих пор.

class BuildABox extends HTMLElement {
  constructor() {
    super();
    this.querySelectorAll('[data-tooltip]').forEach((button) =>
      button.addEventListener('click', this.toggleTooltip.bind(this))
    );
  }

  toggleTooltip(e) {
    e.preventDefault();
    const toolTip = e.currentTarget.lastChild.previousSibling;
    toolTip.classList.toggle('tw-invisible');
  }
}

customElements.define('build-a-box', BuildABox);
<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 %} This is tooltip to hide/show {% endcomment %}
    <div
      id = "tooltip"
      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"
                              >
      <p>{{ block.settings.product_description }}</p>
    </div>
  </div>
</button>
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
0
4
65
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Разъяснить мои предыдущие комментарии, которые я удалил; Я немного обновил ваш код и добавил немного CSS, чтобы показать его здесь. У меня есть элемент данных, чтобы выбрать цель, а затем использовать ее в обработчике кликов.

class BuildABox extends HTMLElement {
  constructor() {
    super();
    this.querySelectorAll('[data-tooltip-target]').forEach((button) => {
      button.addEventListener('click', this.toggleTooltip.bind(this))
    });
  }

  toggleTooltip(e) {
    e.preventDefault();
    const mytarget = e.currentTarget.dataset.tooltipTarget;
    const toolTip = e.currentTarget.querySelector(`[data-tooltip = "${mytarget}"]`);
    toolTip.classList.toggle('tw-invisible');
  }
}

customElements.define('build-a-box', BuildABox);
.tw-invisible {
  display: none;
}

.tooltip-text {
  color: blue;
  font-size: 1.5rem;
}
<build-a-box>
  <button id = "info-btn" aria-label = "Information" type = "button" data-info = "{{ block.settings.product_description }}" data-tooltip-target = "mine">
  <div 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>
    <tool-tip data-tooltip = "mine" class = "tw-invisible">
    <span class = "tooltip-text">This is tooltip to hide/show</span>
    </tool-tip>
    <div class = "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">
      <p>{{ block.settings.product_description }}</p>
    </div> 
  </div>
</button>
</build-a-box>
Ответ принят как подходящий

Вы не хотите создавать зависимости, поэтому сохраните как можно больше логики внутри веб-компонента.

Здесь используется shadowDOM, потому что он сохраняет размер веб-компонента
и вы можете стилизовать с помощью глобального CSS, используя ::part

Ключевое понятие: <my-button tooltip>
Атрибут tooltip определяет, виден он или нет.

Я добавил дополнительные стили, чтобы показать больше вариантов стилей.
Для более подробной информации о <slot> и ::slotted читайте: ::slotted CSS-селектор для вложенных дочерних элементов в слоте shadowDOM

тот же код в: https://jsfiddle.net/WebComponents/xg3ns6od/

customElements.define('my-button', class extends HTMLElement {
  constructor() {
    super().attachShadow({mode:"open"}).innerHTML =
    `<style>`+
      `button{ width:120px; cursor:pointer } ::slotted(div){ pointer-events:none }` + 
      `[name = "tooltip"]::slotted(div) { color:blue; font-size: 1.2rem }`+
      `[name = "label"]::slotted(div) { font-size:1em;font-weight:bold }`+
      `:host([tooltip]) svg { fill:green!important } `+
      `:host(:hover:not([tooltip])) path{ scale:1.2; transform-origin: center }` +
      `:host(:not([tooltip])) [name = "tooltip"]::slotted(div) { visibility:hidden } `+
    `</style>`+
    `<button part = "button"><svg part = "icon" viewBox = "0 0 2400 2400">`+
      `<path fill-rule = "evenodd" d = "m225 1200c0-539 437-975 975-975s975 437 975 975-437 975-975 975-975-436-975-975zm871-144c115-57 244 46 213 171l-71 284 4-2a75 75 90 0167 134l-4 2c-115 57-244-46-213-171l71-284-4 2a75 75 90 11-67-134l4-2zm104-156a75 75 90 100-150 75 75 90 000 150z"/>`+
      `</svg><slot name = "tooltip"></slot>`+
            `<slot name = "label"></slot></button>`;
  }
  connectedCallback(){
    this.onclick = () => this.tooltip = !this.tooltip;
    this.globalListener = document.addEventListener("click",
                                  (evt) => this.tooltip = evt.target == this )
  }
  get tooltip()   { return this.hasAttribute("tooltip") }
  set tooltip(val){ this.toggleAttribute("tooltip",val) }

  disconnectedCallback(){
    document.removeEventListener("click", this.globalListener);
  }
});
/* style parts IN shadowDOM */
my-button::part(icon){ fill:red }

/* style lightDOM! */
my-button[tooltip] [slot = "tooltip"] { background:lightgreen }
<my-button>
  <div slot = "tooltip">Tooltip 1</div>
  <div slot = "label">Product Description</div>
</my-button>
<my-button tooltip>
  <div slot = "tooltip">Tooltip 2</div>
  <div slot = "label">Product Description</div>
</my-button>
<my-button>
  <div slot = "tooltip">Tooltip 3</div>
  <div slot = "label">Product Description</div>
</my-button>

Дэнни, большое спасибо, это действительно много значит для меня. Очень элегантное решение. Спасибо за отзыв о веб-компонентах. Я только начинаю с ними, так что это очень полезно.

Mike Haslam 10.02.2023 20:05

Другие вопросы по теме