第一句子网 - 唯美句子、句子迷、好句子大全
第一句子网 > dom元素滚动条高度 js_DOM 事件与事件委托

dom元素滚动条高度 js_DOM 事件与事件委托

时间:2021-01-14 02:51:36

相关推荐

dom元素滚动条高度 js_DOM 事件与事件委托

点击事件

<div class = 爷爷><div class = 爸爸><div class = 儿子>文字</div></div></div>// 即 .爷爷 > .爸爸 > .儿子// 给三个 div 分别添加事件监听 fnYe/fnBa/fnEr

提问1:点击了谁

点击文字,算不算点击儿子?点击文字,算不算点击爸爸?点击文字,算不算点击爷爷?答案:都算

提问2:调用顺序

点击文字,最先调用 fnYe / fnBa / fnEr 中的哪一个函数?答案:都行IE5 认为先调 fnEr,网景认为先调 fnYe,然后掐上了最后闹到了 W3C

2002年,W3C 发布标准

规定浏览器应该同时支持两种调用顺序首先按 爷爷 => 爸爸 => 儿子 顺序看有没有函数监听然后按 儿子 => 爸爸 => 爷爷 顺序看有没有函数监听由监听函数就调用,并提供事件信息,没有就跳过

术语

从外向内找监听函数,叫事件捕获从内向外找监听函数,叫事件冒泡

疑问:这样是不是把 fnYe / fnBa / fnEr 都调用两次呐?=> 开发者可以自己选择把 fnYe 放在捕获阶段还是放在冒泡阶段

示意图

addEventListener

事件绑定API

baba.attachEvent('onclick',fn) // 冒泡 => IE5*baba.addEventListener('click',fn) // 捕获 => 网景baba.addEventListener('click',fn,bool) // W3C

如果 bool 不传或为 falsy

就让 fn 走冒泡,即当浏览器在冒泡阶段发现 baba 有 fn 监听函数,就会调用 fn ,并提供事件信息。

如果 bool 为 true

就让 fn 走捕获,即当浏览器在捕获阶段发现 baba 有 fn 监听函数,就会调用 fn,并提供事件信息。

一个特例

背景

只有一个 div 被监听(不考虑父子同时被监听)fn 分别在捕获阶段和冒泡阶段监听 click 事件用户点击的元素就是开发者监听的

代码

div.addEventLisenter('clicl', f1)div.addEventLisenter('clicl', f2, true)请问 f1 先执行还是 f2 先执行?如果把两行代码调换位置后,请问哪个先执行?答案:谁先监听谁先执行。 => 这是一个特例

target V.S. currentTarget

区别

e.target - 用户操作的元素e.currentTarget - 开发者监听的元素this 是 e.currentTarget,不推荐使用

举例

div > span {文字},用户点击文字e.target 就是 spane.currentTarget 就是 div

取消冒泡

捕获不可取消,但冒泡可以

e.stopPropagation() 可中断冒泡,浏览器不再向上走一般用于封装某些独立的组件

不可取消冒泡

有些事件不可取消冒泡

MDN 搜索 scroll event ,看到 Bubbles 和 Cancelable Bubbles 的意思是该事件是否冒泡Cancelable 的意思是开发者是否可以取消冒泡

上面提到 scroll ,那么如果阻止滚动

首先scroll 事件不可取消冒泡

阻止 scroll 默认动作没用,因先有滚动才有滚动事件要阻止滚动,可阻止 wheel 和 touchstart 的默认动作需要找准滚动条所在的元素JS Bin​但是滚动条还能用,可用 CSS 让滚动条 display: none

CSS 也可以

使用 overf: hidden 可以直接取消滚动条但此时 JS 依然可以修改 scrollTop

事件委托(event.target 属性可以实现事件委托)

场景一

现在需要给100个按钮添加点击事件,怎么办?答:监听这100个按钮的祖先,等冒泡的时候判断 target 是不是这100个按钮中的一个。

场景二

现在要监听目前不存在的元素的点击事件,怎么办答:监听祖先,等点击的时候看看是不是我想要监听的元素即可

优点

省监听数(内存)可以监听动态元素

封装事件委托

要求

函数 on('click', '#div1', 'button',fn)当用户点击 #div1 里的 button 元素时,调用 fn 函数需要用到事件委托

答案一

判断 target 是否匹配 'button'

const div1 = document.querySelector("#div1");setTimeout(() => {const button = document.createElement("button");button.textContent = "click 1";div1.appendChild(button);}, 1000); // 一秒钟后在 div1 中添加button元素on("click", "#div1", "button", () => {console.log("button被点击了");});function on(eventType, element, selector, fn) {if (!(element instanceof Element)) {element = document.querySelector(element);}element.addEventListener(eventType, (e) => {const t = e.target;if (t.matches(selector)) {fn(e);}});} // 封装函数 on

首先通过这个 on 函数理解事件委托,给传入 element 参数的元素添加一个监听,然后判断当前的 target 是否满足 selector,如果满足就调用函数,如果不满足就放过。

但是这个方法是有误区的,如果 传入 selector 参数的元素还被 span 包围了,也就是说 button 元素中还含有一个 span ,然后 span 元素里有文字内容,这时我点击 button,委托事件是不会触发的,因为实际上我点击的是 span 元素,例子如下所示:

const div1 = document.querySelector("#div1");setTimeout(() => {const button = document.createElement("button");const span = document.createElement("span");span.textContent = "click 1";button.appendChild(span);div1.appendChild(button);}, 1000);on("click", "#div1", "button", () => {console.log("button被点击了");});function on(eventType, element, selector, fn) {if (!(element instanceof Element)) {element = document.querySelector(element);}element.addEventListener(eventType, (e) => {const t = e.target;if (t.matches(selector)) {fn(e);}});}

答案二

递归判断 target / target 的爸爸 / target的爷爷

function on(eventType, element, selector, fn) {if (!(element instanceof Element)) {element = document.querySelector(element);}element.addEventListener(eventType, (e) => {let el = e.target;while (!el.matches(selector)) {if (element === el) {el = null;break;}el = el.parentNode;}el && fn.call(el, e, el);});return element;}

JS 支持事件吗?

支持,也不支持。上面所说的 DOM 事件不属于 JS 的功能,属于浏览器提供的 DOM 的功能JS 只是调用了 DOM 提供的 addEventListener

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。