JQuery Найти ближайший элемент внутри div на основе события mousemove

Google использует функцию обратной связи , которая выделяет цвет фона элементов контента (например: p, div, ul, h2 и т. д.), когда пользователь наводит указатель мыши на элемент div с правой стороны контента.

Я считаю, что следующий класс CSS применяется к элементу, чтобы выделить его фон:

.inline-feedback__highlight {
    background: #d2e3fc;
    -webkit-border-radius: .3125rem;
    border-radius: .3125rem;
}

Используя jQuery или JavaScript и CSS, я хотел бы добиться того же результата.

Мой вопрос

Как я могу определить, какой ближайший элемент в <div id = "content">...</div>?

Я думал о какой-то форме координат x, y и смещении от верхней части содержимого div.

Мой код

$(function() {
  let halfBtnHt = Math.ceil($('#track-button-div').height() / 2);

  $('#track-container').on('mousemove', function(e) {
    // console.info(e.offsetX, e.offsetY);
    $('#track-button').css({
      'transform': `translateX(0) translateY(${e.offsetY - halfBtnHt}px)`,
      'visibility': 'visible',
    })

  }).on('mouseout', function(e) {
    $('#track-button').css({
      'visibility': 'hidden'
    })
  })

})
#content-container {
  position: relative;
  border: 1px solid black;
  width: 500px;
  height: auto;
  margin: 100px auto;
}

#content {
  padding: 2rem;
}

#track-container {
  position: absolute;
  text-align: center;
  top: 0;
  bottom: 0;
  width: 64px;
  right: -56px;
  z-index: 1;
}

#track-button {
  width: 42px;
  height: 42px;
  border-radius: 30px;
  pointer-events: none !important;
}

#track-button-div {
  visibility: hidden;
}
<!DOCTYPE html>
<html lang = "en">

<head>
  <meta charset = "UTF-8">
  <title>Title</title>
  <link rel = "stylesheet" href = "https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" integrity = "sha384-TX8t27EcRE3e/ihU7zmQxVncDAy5uIKz4rEkgIXeMed4M0jlfIDPvg6uqKI2xXr2" crossorigin = "anonymous">
  <link rel = "stylesheet" href = "https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.1/css/all.min.css" integrity = "sha512-+4zCK9k+qNFUR5X+cKL9EIR+ZOhtIloNl9GIKS57V1MyNsYpYcUrUeQc9vNfzsWfV28IaLL3i96P9sdNyeRssA= = " crossorigin = "anonymous" />
  <link rel = "stylesheet" href = "style.css">
</head>

<body>
  <div id = "content-container">
    <div id = "content">
      <div>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Aliquam, iusto? Lorem ipsum dolor sit amet, consectetur adipisicing elit. Consequuntur dolores earum esse eveniet libero minima pariatur repellat sed sunt ut?</div>
      <pre class = "prettyprint linenums prettyprinted">
                    <ol class = "linenums">
                        <li class = "L0">Hey</li>
                    </ol>
                </pre>
      <p>Blanditiis corporis ducimus laudantium nisi pariatur quasi repellat sunt, ut? Consequuntur dolores earum</p>
    </div>
    <div id = "track-container">
      <div id = "track-button-div">
        <button id = "track-button" class = "btn btn-outline-primary">
                        <i class = "fas fa-quote-right"></i>
                    </button>
      </div>
    </div>
  </div>
  <script src = "https://code.jquery.com/jquery-3.5.1.slim.min.js" integrity = "sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj" crossorigin = "anonymous"></script>
  <script src = "https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js" integrity = "sha384-ho+j7jyWK8fNQe+A12Hb8AhRq26LrZ/JpcUGGOn+Y7RsweNrtN/tE3MoK7ZeZDyx" crossorigin = "anonymous"></script>
  <script src = "track.js"></script>
</body>

</html>

Вот как выглядит функция обратной связи Google

Поведение ключевого слова "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) для оценки ваших знаний,...
3
0
127
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

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

Проверьте эту песочницу на рабочем примере

Ключевым моментом здесь является использование функции elementFromPoint, песочница должна просто давать общее представление, и вы можете адаптировать ее к своим потребностям!

+1 Отличный ответ. Я выбрал ответ MMDM, потому что он дал мне именно то, что мне было нужно. Я продолжал натыкаться на document.elementFromPoint(x,y), но не мог придумать, как это сделать. Ваше решение очень полезно!

Jarad 12.12.2020 19:52

Не беспокойтесь, рад помочь.

Renan Souza 12.12.2020 19:56
Ответ принят как подходящий

Посмотрите на фрагмент ниже:

(function ($) {
    'use strict';

    $(function () {
        var
            namespace = 'mmdm',
            //-----
            mainElementID = '#__elements_container',
            highlightClass = 'founded-element__highlight',
            //-----
            mainElement = $(mainElementID),
            movableElementContainer = $('#__movable_element_container'),
            movableElement = $('#__movable_element');

        // some utility

        function getTouch(event) {
            var touch = event;
            if (('ontouchstart' in document.documentElement) || navigator.maxTouchPoints > 0) {
                touch = event.originalEvent.touches && event.originalEvent.touches.length ? event.originalEvent.touches[0] : event;
                if (event.type === 'touchstart' || event.type === 'touchmove') {
                    touch = event.targetTouches[0] || event.changedTouches[0];
                }
            }
            return touch;
        }

        // define function(s)
        function removeHighlightClass() {
            mainElement.find('*').removeClass(highlightClass);
        }

        function findElementsWithSameYNHighlightIt(e) {
            var x, y, meOffset, el;
            meOffset = mainElement.offset();
            x = (e.pageX - meOffset.left) / 2;
            y = e.pageY - $(window).scrollTop();

            el = document.elementFromPoint(x, y);
            if (!$(el).is(mainElement) && $(el).closest(mainElementID).length) {
                $(el).addClass(highlightClass);
            }
        }

        function showMovableElement() {
            movableElement.addClass('show');
        }

        function hideMovableElement() {
            movableElement.removeClass('show');
        }

        function moveMovableElement(e) {
            var y, mecTop = movableElementContainer.offset().top;
            y = e.pageY;
            // bound move to the main movable container
            if (y >= mecTop && y <= (mecTop + movableElementContainer.outerHeight())) {
                movableElement.css({
                    'top': y - mecTop - (movableElement.outerHeight() / 2)
                });
            }
            removeHighlightClass();
        }

        // attach event(s)
        movableElementContainer
            .on('mousemove.' + namespace + ' touchmove.' + namespace + ' mouseenter.' + namespace + ' touchstart.' + namespace, function (e) {
                if (!e.defaultPrevented && e.cancelable) {
                    e.preventDefault();
                }
                //-----
                var touch = getTouch(e);
                showMovableElement();
                moveMovableElement(touch);
                findElementsWithSameYNHighlightIt(touch);
            }).on('mouseleave.' + namespace + ' touchend.' + namespace, function (e) {
            if (!e.defaultPrevented && e.cancelable) {
                e.preventDefault();
            }
            //-----
            hideMovableElement();
            removeHighlightClass();
        });
    });
})(jQuery);
* {
  box-sizing: border-box;
}

#__elements_main_container {
  display: flex;
}

#__elements_container {
  width: 500px;
}

#__movable_element_container {
  position: relative;
  width: 40px;
}

#__movable_element_container::after {
  content: '';
  position: absolute;
  top: 0;
  left: 50%;
  width: 1px;
  height: 100%;
  background-color: #ccc;
  transform: translate(-50%);
  z-index: 1;
}

#__movable_element  {
  position: absolute;
  display: none;
  align-items: center;
  justify-content: center;
  left: 50%;
  width: 40px;
  height: 40px;
  text-align: center;
  border-radius: 50rem;
  border: 1px solid #ccc;
  background-color: #fff;
  box-shadow: 0 2px 5px rgba(0, 0, 0, .26);
  transform: translate(-50%);
  z-index: 2;
}

#__movable_element.show {
  display: flex;
}

.founded-element__highlight {
    background-color: #cecdff;
    border-radius: 3px;
}
<link href = "https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.css" rel = "stylesheet"/>
<script src = "https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<div id = "__elements_main_container">
  <div id = "__elements_container">
    <h1>
      A heading tag!
    </h1>
    <p>
      Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
    </p>
    <ul>
      <li>First list item</li>
      <li>Second list item</li>
    </ul>
  </div>
  <div id = "__movable_element_container">
    <i id = "__movable_element" class = "fa fa-quote-right"></i>
  </div>
</div>

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