DOM事件模型
DOM即文档对象模型。是HTML和XML文档的编程接口。
DOM事件:就是用户或浏览器自身执行的某种动作。click,load,onmouseover,onmouseout。
DOM事件流:描述的是从页面中接收事件的顺序
DOM事件流包括三个阶段:
- 事件捕获阶段(capture phase
- 处于目标阶段(target phase)
- 事件冒泡阶段(bubbling phase)

DOM事件模型分为两类
捕获事件:
从外向内找监听函数,DOM树上的表现就是由根节点传播到叶子节点。
冒泡事件:
从内向外找监听函数,DOM树上就是事件从叶子节点传播到根节点。
W3C事件模型:首是进入捕获阶段,直到达到目标元素,再进入冒泡阶段
标准的事件处理模型分为三个阶段:
- 父元素中所有的捕捉型事件(如果有)自上而下地执行
- 目标元素的冒泡型事件(如果有)
- 父元素中所有的冒泡型事件(如果有)自下而上地执行
示例代码:点击这里
注册事件监听
son.addEventListener("event", fn, bool);// 如果bool不填 就默认是冒泡事件 如果bool为ture就是监听事件
target 与 currentTarget的区别
- e.target -用户操作的元素
- e.currentTarget -程序员监听的元素
- this是e.currentTarget,不推荐使用它
特例:如果监听的是用户点击的div,也就是没有考虑父子同时被监听
div.addEventListener("click", fn);div.addEventListener("click", fn,ture);
谁先监听谁先执行
<body><div class="son">文字</div><script>//冒泡let son = document.querySelector(".son");son.addEventListener("click", () => {console.log(1)});// 监听son.addEventListener( "click",() => { console.log(2)},true);</script></body>// 返回 1 , 2
我们可以取消冒泡但是不能取消监听 e.stopPropagation()这个可以中断冒泡,浏览器就不会再向上走。
不可冒泡事件
引用知乎的一篇文章:JavaScript 中那些不会冒泡的事件
UI事件
- load
- unload
- scroll
- resize
焦点事件
- blur
- focu
鼠标事件
- mouseleave
- mouseenter
例如 scroll事件
scroll 事件在元素滚动条在滚动时触发。
我们创建一个网页测试以下
// 样式#container {width: 100%;height: 400px;border: 1px solid red;}#outer {width: 80%;height: 600px;border: 1px solid blue;}#inner {width: 40%;height: 900px;border: 1px solid pink;}
// 网页本体<div id="grandFather"><div id="father"><div id="son">123</div></div></div>
如下图所示

加上script设置成了冒泡事件
<script>father.addEventListener("scroll",function () {console.log("滚动了");});</script>
如果它是一个冒泡事件当鼠标在#son和#father区域滑动时就会在控制台输出滚动了。但是没有输出任何内容。他就是一个不可冒泡事件。同样也对他没法进行e.stopPropagation()阻止冒泡。
我们阻止滚动就用的另一种方法wheel和touchtstart
<script>// 去除鼠标滚动father.addEventListener("wheel", function (e) {console.log("滚动了");e.preventDefault();});// 去除手机触屏滚动father.addEventListener("touchstart", function (e) {console.log("滚动了");e.preventDefault();});</script>
自定义事件
创建了一个名称为"frank"可以冒泡但是不能不能阻止冒泡的自定义事件
<body><div id="div1"><button id="button1">点击触发 frank 事件</button></div><script>let button = document.querySelector("#button1");button.addEventListener("click", () => {const event = new CustomEvent("frank", {detail: { name: "frank", age: 18 },bubbles: true,});button.dispatchEvent(event);});div1.addEventListener("frank", (e) => {console.log("frank事件触发了");console.log(e.detail);});</script></body>
事件委托
事件委托就是利用事件的冒泡原理,委托他们的父级代为执行事件。
举例:在一个公司里面有同事的快递到了,他有2个方式,一是自己去公司外面拿快递,二是委托前台的同事代为签收。当然第二种方式更加的便捷,同时即使公司来了新员工,前台同事也会在收到寄给新员工的快递后核实并代为签收。
下面就是来了一个新同事span的例子。
<body><div id="div1"></div><script>setTimeout(() => {const button = document.createElement("button");button.textContent = "click1";div1.appendChild(button);}, 1000);div1.addEventListener("click", (e) => {// target就可以表示为当前的事件操作的domconst t = e.target;// 获取标签的小写if (t.tagName.toLowerCase() === "button") {console.log("button 被点击了");}});</script></body>
封装好的事件委托
<body><div id="div1"></div><script>setTimeout(() => {const button = document.createElement("button");button.textContent = "click1";div1.appendChild(button);}, 1000);on("click", "#div1", "button", () => {console.log("button被点击了2");});function on(eventType, element, selector, fn) {if (!(element instanceof Element)) {element = document.querySelector(element);}element.addEventListener(eventType, (e) => {const t = e.target;// 判断传进来的element是否符合buttonwhile (!t.matches(selector)) {// 找到最顶层 也就是 #div1 找不到了就停止if (element === t) {t = null;break;}// 传进的元素等于他的爸爸t = t.parentNode;}t && fn.call(t, e, t); // 第一个是 this});return element;}</script></body>
注意:JS不支持事件 ,JS只是调用了DOM提供的addEventListener
