Подсказка браузера по умолчанию не отображается из-за устранения дребезга RxJS

По сути, я хочу добиться того, чтобы прослушать событие «mousemove», прикрепленное к документу, и как только я наведу курсор на элемент, я проверяю, есть ли у него переполненный текст, и если это так, я обрезаю его и добавляю атрибут title к целевому элементу с полным текстом, чтобы когда пользователь наводит на него курсор, браузер показывает всплывающую подсказку по умолчанию с этим текстом.

Эта логика прекрасно работает сама по себе, но у нее есть серьезный недостаток. Это убивает производительность моего приложения, потому что я использую внутри него getComputedStyle().

Чтобы решить эту проблему, я попытался использовать RxJS debounce, и он отлично работает. Но если пользователь быстро перемещает мышь, а затем останавливается, так что для этого элемента возникает только одно событие, тогда всплывающая подсказка добавляется в DOM, но не отображается.

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

fromEvent(document, 'mouseenter')
.pipe(
  debounceTime(20),
  tap(($event: Event) => {
    this.addTooltip($event);
  })
)
.subscribe();

Вопрос в том, знает ли кто-нибудь, как я могу обойти эту проблему?


person Mykola    schedule 23.03.2020    source источник


Ответы (1)


Ну, я думаю, вы можете попробовать вызвать событие mousemove в коде, используя метод Element.dispatchEvent(). Я попытался сделать что-то в качестве примера в этом демонстрация stackblitz (да, это angular, но я не использую функцию andy angular, кроме разделения задач markup-javascript-css => все остальное - это просто чистый javascript). В основном, что я сделал, это:

<p title="house">
  Start editing to see some magic happen :)
</p>
// track the html elements that currently have a title modified
// this avoids additional unnecessary listeners on a single HTML element
private elementWithListenerAdded = new Set();

...

fromEvent(document, "mousemove")
  .pipe(
    debounceTime(20),
    tap(($event: MouseEvent) => {
      this.addTooltip($event);
    })
  )
  .subscribe();

...

addTooltip(evt: MouseEvent) {
  const $tag = evt.target;

  // I'm assuming that you don't want any tooltip on
  // header, HTML or body tags
  if (
    ($tag as any).tagName === "HEADER" ||
    ($tag as any).tagName === "HTML" ||
    ($tag as any).tagName === "BODY" ||
    this.elementWithListenerAdded.has($tag)
  ) {
    return;
  }

  const elementWithListenerAdded = this.elementWithListenerAdded;

  elementWithListenerAdded.add($tag);

  // remove the event listener when the mouse leave the element
  // and restore the original title
  const originalTitle = ($tag as any).getAttribute("title");
  function removeEventListener() {
    $tag.removeEventListener("mouseleave", this);
    elementWithListenerAdded.delete($tag);
    ($tag as any).setAttribute("title", originalTitle);
  }

  $tag.addEventListener("mouseleave", removeEventListener);

  ($tag as any).setAttribute("title", "just a test");

  ($tag as any).dispatchEvent(
    new MouseEvent("mousemove", {
      bubbles: true,
      cancelable: true,
      view: window
    })
  );
}

person julianobrasil    schedule 24.03.2020