javascript - jQuery Find Closest Element Inside div Based on mousemove Event
问题描述
Google uses a feedback feature that highlights the background color of content elements (ex:p
, div
, ul
, h2
, etc.) when the user mouses over a div to the right side of the content.
I believe the following CSS class is applied to the element to highlight its background:
.inline-feedback__highlight {
background: #d2e3fc;
-webkit-border-radius: .3125rem;
border-radius: .3125rem;
}
Using jQuery or JavaScript and CSS, I'd like to achieve the same result.
My Question
How can I identify what the closest element in <div id="content">...</div>
is?
I was thinking some form of x,y coordinates and offset from the top of the content div.
My Code
$(function() {
let halfBtnHt = Math.ceil($('#track-button-div').height() / 2);
$('#track-container').on('mousemove', function(e) {
// console.log(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/bootstrap@4.5.3/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/bootstrap@4.5.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-ho+j7jyWK8fNQe+A12Hb8AhRq26LrZ/JpcUGGOn+Y7RsweNrtN/tE3MoK7ZeZDyx" crossorigin="anonymous"></script>
<script src="track.js"></script>
</body>
</html>
Here's what Google's Feedback Feature Looks Like
解决方案
看下面的片段:
(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>
推荐阅读
- c# - 如何同步调用异步方法?
- c# - 当空引用似乎不可能时,为什么我们会收到可能的取消引用空引用警告?
- ios - 打开 Thread Sanitizer 会产生信号 SIGABRT
- java - Java Socket 不会出错但不能正常工作(?)
- mediawiki - 使用 Mediawiki 的本地域上的 LDAP
- mysql - 只能使用 --skip-grant-tables 参数访问 mySQL(检查所有其他线程)
- android - 图标到边缘
- android - 打开whatsapp //:在webview中
- javascript - 非常基本的 React + NodeJS 获取:为什么我的响应不是我想要的?
- xcode - 无法按顺序对 SwiftUI 图像进行动画处理或过渡