touchstart 事件中 preventdefault

问题补充:touchstart 事件中 ev.preventdefault 不能阻止默认滚动事件?

事件执行机制

js事件执行分为三个阶段,捕获阶段,获取目标,冒泡阶段。

  • 捕获阶段 (从根节点开始顺着目标节点构建一条事件路径,即事件由页面元素接收,逐级向下,到具体的元素)
  • 目标阶段 (到达目标节点,即元素本身)
  • 冒泡阶段 (从目标节点顺着捕获阶段构建的路径回去, 即跟捕获相反具体元素本身,逐级向上,到页面元素)

举个例子说明一下:

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title></title>
</head>
<body>
<div id="myDiv">Click me!</div>
</body>
<script>
    document.body.addEventListener('click', function(ev){
        console.log("捕获阶段,点中了body")
    }, true)
    document.querySelector("#myDiv").addEventListener('click', function(ev){
        console.log("捕获阶段,点中了div#myDiv")
    }, true)
        document.body.addEventListener('click', function(ev){
        console.log("冒泡阶段,点中了body")
    })
    document.querySelector("#myDiv").addEventListener('click', function(ev){
        console.log("冒泡阶段,点中了div#myDiv")
    })
</script>	
</html>

得到结果:

捕获阶段,点中了body
捕获阶段,点中了div#myDiv
冒泡阶段,点中了div#myDiv
冒泡阶段,点中了body

事件监听器

DOM规范初期,定义了三个参数

type: 监听事件

listener:监听事件执行函数

useCapture:捕获阶段/冒泡阶段(true/false) 执行

addEventListener(type, listener, useCapture)

之后因为事件在捕获阶段执行的概率少之又少,useCapture在事件中也可以省略

addEventListener(type, listener[, useCapture])

2015年W3C对DOM事件监听器做了一次修改

addEventListener(type, listener[, useCapture ||, options])
options配置项
options: {
    capture: false, 
    passive: false, 
    once: false
}

capture(等同useCapture)

​ 默认 false

​ 表示 listener 会在该类型的事件捕获阶段传播到该 EventTarget 时触发

passive

​ 默认false

​ 设置为true时,表示 listener 永远不会调用 preventDefault()。如果 listener 仍然调用了这个函数,客户端 将会忽略它并抛出一个控制台警告,passive为true时,执行e.preventDefault()方法,报错(由于目标被视 为被动,无法在被动事件侦听器中阻止默认)

once

​ 是否只执行一次

问题解决(touchstart 事件中 ev.preventdefault 失效)

目前已经了解了事件部分机制,再来说说 preventdefaultpassive

在浏览器中,即使给触摸事件添加一个空函数监听器也会导致浏览器卡顿,而实际操作过程中调用preventDefault()概率占有20%,由于浏览器无法事先知道监听器是否会调用preventDefault(),它不得不执行完整的监听函数才能决定是否滚动页面,passive的实现是让浏览器无需考虑事件是否会阻止其默认行为。

在之前的描述中,passive的默认值为false,这个并不准确,在firefox进行了两类测试。

// a标签preventDefault测试
document.querySelector('a.element').addEventListener('click',function(ev){ev.preventDefault()}, false)
// 此时ev.preventDefault()对该元素默认点击行为进行了阻止
// 表现为 passive: false

// 页面滚动测试
document.addEventListener('DOMMouseScroll', function(ev){ev.preventDefault()}, false)
// 此时会报出警告忽略一个注册为 ‘passive’ 的监听器的事件类型为 ‘DOMMouseScroll’ 的 ‘preventDefault()’ 调用。
// 表现为 passive: true

// 页面滚动阻止测试
document.addEventListener('DOMMouseScroll', function(ev){ev.preventDefault()}, {passive: false});  
// 此时ev.preventDefault()对该元素默认滚动行为进行了阻止
// 表现为 passive: false

可以看出,页面滚动已忽略preventDefault事件监听,passive 默认为 true

touchstart 事件中 ev.preventdefault 失效问题,则需要开发人员对页面监听事件手动添加{passive: false},目前已经可以阻止页面滚动事件,但新的问题又出现了,添加滚动行为阻止会导致总是阻止页面滚动。

阻止页面滚动以及移除页面滚动

阻止页面滚动我们已经做的很好,通过配置{passive: false},即可阻止滚动,但是我们实际情况可能是在弹出框存在时阻止页面滚动,关闭弹出框可继续滚动,因此,不能使用匿名函数设置监听事件。

举个例子:

/**
 * 使用匿名函数
 * 阻止页面滚动 > Y
 * 还原页面滚动 > N
 */
document.addEventListener('DOMMouseScroll', function(ev){ev.preventDefault()}, {passive: false});
document.removeEventListener('DOMMouseScroll', function(ev){ev.preventDefault()}, {passive: true});

/**
 * 使用具名函数
 * 阻止页面滚动 > Y
 * 还原页面滚动 > Y
 */
function stopScroll(ev){ev.preventDefault()}
document.addEventListener('DOMMouseScroll', stopScroll, {passive: false});
document.removeEventListener('DOMMouseScroll', stopScroll, {passive: true});

若有好的想法或意见,请不吝赐教~

参考文档:

https://www.cnblogs.com/wxcbg/p/10452985.html

https://www.cnblogs.com/ziyunfei/p/5545439.html

https://blog.csdn.net/qq_38280242/article/details/108411169

https://blog.csdn.net/qq_42098849/article/details/104582160

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值