javascript - 在父容器的 mouseover 和 mouseleave 上切换 preventDefault()
问题描述
我有一些容器,里面有包含链接的子容器。
发生的情况是,当用户将鼠标悬停在父容器上以显示子容器时,链接在前 2 秒内被禁用。如果用户在单击链接之前将鼠标移开,则此行为将使用“hasBeenHovered”变量重置,该变量在 mouseleave 事件中从 true 变为 false。
我面临的两个问题是:
a)我不能让它只在被悬停的父级上工作 - 它遍历所有这些并显示它们;
b)在移动设备上,无论如何都会将不透明度恢复为 1 并通过重新点击再次禁用链接(因此重新点击有效地作为 mouseleave 事件工作?)。如果这非常复杂,我可能只是拥有它,因此它一直可见,直到父容器到达视口的顶部。
虽然代码沙箱在下方,但它显示“未捕获的 TypeError:allowLinks 不是函数”,但在 CodePen 上演示是否有效?
非常感谢您的帮助。
艾米丽
代码笔: https ://codepen.io/emilychews/pen/rNjXMee
var parent = document.querySelectorAll(".parent");
var child = document.querySelectorAll(".child");
var link = document.querySelectorAll(".link");
var hasBeenHovered = false;
var listener = function (e) {
e.preventDefault();
};
// prevent default on all specific links
link.forEach(function (item) {
item.addEventListener("click", listener);
});
// mouseover that changes opacity to 1 and removes prevent default on links
parent.forEach(function (item) {
item.addEventListener("mouseover", function (event) {
child.forEach(function (item) {
item.style.opacity = "1";
item.style.transition = "opacity .5s";
});
// remove prevent Default
if (hasBeenHovered === false) {
function allowLinks() {
link.forEach(function (item) {
item.removeEventListener("click", listener);
hasBeenHovered = true;
});
}
}
setTimeout(function () {
allowLinks();
}, 2000);
}, false );
});
// mouseleave event re-adds opacity: 0 and re-adds prevent default
parent.forEach(function (item) {
item.addEventListener("mouseleave", function (event) {
child.forEach(function (item) {
item.style.opacity = "0";
item.style.transition = "opacity .5s";
});
// re-add prevent Default
if (hasBeenHovered === true) {
link.forEach(function (item) {
item.addEventListener("click", listener);
hasBeenHovered = false;
});
}
}, false );
});
body {
margin: 0;
display: flex;
align-items: center;
justify-content: center;
width: 100%;
height: 100vh;
}
.parent {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
width: 20rem;
height: 20rem;
background: lightblue;
margin: 1rem;
}
.child {
opacity: 0; /* hides child container*/
padding: 1rem;
background: red;
}
a {
color: #fff;
display: block;
margin: 1rem 0;
}
<div class="parent">
<div class="child">
<a target="_blank" href="https://google.com" class="link">This will work after 2 seconds of mouseover</a>
<a target="_blank" href="https://google.com" class="link">This will work after 2 seconds of mouseover</a>
</div>
</div>
<div class="parent">
<div class="child">
<a target="_blank" href="https://google.com" class="link">This will work after 2 seconds of mouseover</a>
<a target="_blank" href="https://google.com" class="link">This will work after 2 seconds of mouseover</a>
</div>
</div>
解决方案
为了保留您的大部分原始代码逻辑,我已经修改了很多,但这应该是您的目标。对于移动部分,我建议为触摸处理程序设置一个标志,但请注意它会变得更加复杂,因为移动设备也会响应onclick
处理程序。
由于 StackOverflow 安全性,这些链接在代码段中不起作用,因此添加了控制台日志,但如果您复制到 CodePen,这些链接将起作用
const parents = document.querySelectorAll(".parent");
parents.forEach(parent => {
const children = parent.querySelectorAll(".child");
const links = parent.querySelectorAll(".link");
let timeoutId = null; // track the timeout so we can clear it
let enableLinks = false; // should we allow links?
links.forEach(link =>
link.addEventListener("click", evt => {
if (!enableLinks) {
evt.preventDefault(); // hold them hostage
} else {
console.log('StackOverflow prevents links'); // just a placeholder for SO snippet
}
}, true)
);
parent.addEventListener("mouseover", function() {
enableLinks = false; // ensure links are disabled at first
children.forEach(child => child.style.opacity = "1"); // let the children be seen
if (!timeoutId) // make sure there isn't already a timeout
timeoutId = setTimeout(() => enableLinks = true, 2000); // enable links after the 2s
}, false);
parent.addEventListener("mouseleave", function(event) {
children.forEach(child => child.style.opacity = "0"); // hide your children
clearTimeout(timeoutId); // remove the timeout so it can't overlap
timeoutId = null; // clear timeout id
enableLinks = false; // turn off links
}, false);
});
body {
margin: 0;
display: flex;
align-items: center;
justify-content: center;
width: 100%;
height: 100vh;
}
.parent {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
width: 20rem;
height: 20rem;
background: lightblue;
margin: 1rem;
}
.child {
opacity: 0;
/* hides child container*/
padding: 1rem;
background: red;
transition: opacity .5s;
}
a {
color: #fff;
display: block;
margin: 1rem 0;
}
<div class="parent">
<div class="child">
<a target="_blank" href="https://google.com" class="link">This will work after 2 seconds of mouseover</a>
<a target="_blank" href="https://google.com" class="link">This will work after 2 seconds of mouseover</a>
</div>
</div>
<div class="parent">
<div class="child">
<a target="_blank" href="https://google.com" class="link">This will work after 2 seconds of mouseover</a>
<a target="_blank" href="https://google.com" class="link">This will work after 2 seconds of mouseover</a>
</div>
</div>
推荐阅读
- google-bigquery - How to pass list of columns from one table to another table in bigquery
- java - 如何将 LinkedHashMap 转换为 Map
在 Java 中? - symfony - 动态延迟加载服务
- sql-server - SQL Server 在请求事务期间卡住了一张表
- ios - 如何以编程方式获取电话 (iOS) 提供商列表?
- ruby-on-rails - Rails:简洁地打印变量名称和
标签(如果存在) - node.js - 如何使用request-promise从nodejs中的HTTP GET请求获取字符串响应到变量
- python - 如何在没有全局变量的情况下将值传递给回调以进行匿名化?
- selenium - 如何解决 Selenium ChromeDriver Timed out 从渲染器异常接收消息
- ruby-on-rails - 如何访问定制的狂欢模型