事件的三种触发方法
- 标签属性
- DOM属性
- 监听
<input id="elem1" onClick="console.log('标签属性触发')" type="button" value="标签属性触发" />
<input id="elem2" type="button" value="DOM属性触发" />
<input id="elem3" type="button" value="监听触发" />
<script>
// 将函数看作变量设置为elem2.onclick的属性,点击时调用函数
elem2.onclick = () => {
console.log('DOM属性触发');
}
// 将回调函数传入到监听器中,点击后触发
elem3.addEventListener('click', () => {
console.log('监听触发');
})
</script>
DOM事件传播三阶段
目标元素
<form id="form">FORM
<div>DIV
<p>P</p>
</div>
</form>
比如现在点击p层的标签,那么:
event.target
为pthis(=event.currentTarget)
为formevent.eventPhase
:当前阶段(capturing=1,target=2,bubbling=3)
捕获和冒泡
- 捕获阶段(Capturing phase)—— 事件(从 Window)向下走近元素。
- 目标阶段(Target phase)—— 事件到达目标元素。
- 冒泡阶段(Bubbling phase)—— 事件从元素上开始冒泡。
捕获用的比较少,这里主要注意下冒泡
<style>
body * {
margin: 10px;
border: 1px solid blue;
}
</style>
<form>FORM
<div>DIV
<p>P</p>
</div>
</form>
<script>
for(let elem of document.querySelectorAll('*')) {
elem.addEventListener("click", e => alert(`Capturing: ${elem.tagName}`), true);
elem.addEventListener("click", e => alert(`Bubbling: ${elem.tagName}`));
}
</script>
如果你点击了<p>
,那么顺序是:
HTML → BODY → FORM → DIV
(捕获阶段第一个监听器):P
(目标阶段,触发两次,因为我们设置了两个监听器:捕获和冒泡)DIV → FORM → BODY → HTML
(冒泡阶段,第二个监听器)。
每个处理程序都可以访问 event 对象的属性:
event.target
—— 引发事件的层级最深的元素。event.currentTarget(=this)
——处理事件的当前元素(具有处理程序的元素)event.eventPhase
—— 当前阶段(capturing=1,target=2,bubbling=3)。
点击按钮,不会冒泡
点击空白区域,触发时间,弹出the bubbling doesn't reach here
事件处理的两种套路
事件委托
用一个统一的委托函数管理多个事件
<div id="menu">
<button data-action="save">Save</button>
<button data-action="load">Load</button>
<button data-action="search">Search</button>
</div>
<script>
class Menu {
constructor(elem) {
this._elem = elem;
// 为div#menu添加点击事件
/* ★ 为onClick函数绑定上下午,但并没有调用
注意括号的位置,onClick()才代表调用该函数*/
elem.onclick = this.onClick.bind(this);
}
save() {
alert('saving');
}
load() {
alert('loading');
}
search() {
alert('searching');
}
onClick(event) {
// 获取按钮上标注的data
let action = event.target.dataset.action;
if (action) {
this[action]();
}
};
}
// 传入的menu为div#menu
new Menu(menu);
</script>
行为模式
将特征保存在data-toggle-id
中,通过event.target.dateset.toggleId
访问
<button data-toggle-id="subscribe-mail">
Show the subscription form
</button>
<form id="subscribe-mail" hidden>
Your mail: <input type="email">
</form>
<script>
document.addEventListener('click', function(event) {
let id = event.target.dataset.toggleId;
if (!id) return;
let elem = document.getElementById(id);
elem.hidden = !elem.hidden;
});
</script>
阻止浏览器行为两种方式
- HTML属性处return false
event.preventDefault()
,这种方式一般写在函数中较多
<!-- 点击后并不能进行链接跳转 -->
<a href="/" onclick="return false">Click here</a>
<a href="/" onclick="event.preventDefault()">here</a>
自定义事件
由三部分组成:
- 监听和触发事件:
elem.addEventListener('eventName', ……)
- 创建事件:
new CustomEvent('eventName'{bubbles:true,cancelable:true,details:……})
bubbles: true/false
—— 如果为 true,那么事件会冒泡cancelable: true/false
—— 如果为 true,那么“默认行为”就会被阻止
- 分发事件:
elem.dispatchEvent(event)
<h1 id="elem">Hello for John!</h1>
<script>
// 事件附带给处理程序的其他详细信息
elem.addEventListener("hello", function (event) {
alert(event.detail.name);
});
elem.dispatchEvent(new CustomEvent("hello", {
detail: { name: "John" }
}));
</script>
注意:addEventListener必须写在dispatchEvent前面,否则不会触发事件