欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

DOM事件,捕获与冒泡处理,委托模式

程序员文章站 2022-05-06 09:14:19
...

事件流程

3阶段:

1 捕获阶段
事件应当从最顶层元素开始执行 一层层往下 直到最精确的元素
2 处于目标阶段
事件在最精确的元素身上执行
3 冒泡阶段
事件应当从最精确元素开始执行 一层层往上 直到最顶层元素
最顶层元素: IE8及以下中 最顶层元素是document
高级浏览器中 最顶层元素是window
之前介绍的 元素.on事件类型 = 函数 这种方式 是DOM0级事件绑定方式 它只能够绑定到冒泡阶段

			 window.onclick = function() {
		            console.log("window");
		        }
		        document.onclick = function() {
		            console.log("document");
		        }
		        document.documentElement.onclick = function() {
		            console.log("html");
		        }
		        document.body.onclick = function() {
		            console.log("body")
		        }
		        //运行结果:body
									html
									document
									window
DOM2级事件绑定方式

元素.addEventListener(type, handler, boolean);
type 事件类型字符串 不带on
handler 事件处理函数
boolean 布尔值 如果值为true 该绑定是绑定到捕获阶段 否则绑定到冒泡阶段

元素.removeEventListener(type, handler, boolean);
type 事件类型字符串 不带on
handler 事件处理函数
boolean 布尔值 如果值为true 该移除是移除捕获阶段 否则移除冒泡阶段

IE8 浏览器及以下的浏览器 不支持addEventListener
元素.attachEvent(type, handler)
type 事件类型字符串 带on
handler 事件处理函数
没有第三个参数 表示不能绑定到捕获阶段
元素.detachEvent(type, handler)
type 事件类型字符串 带on
handler 事件处理函数

注:想要移除的时候,一定要确保移除的函数就是绑定的函数
注:当处于目标阶段时,事件的执行不分捕获与冒泡,而是依照绑定顺序依次执行

					<script>
					        // 定义变量 简化书写
					        var w = window;
					        var d = document;
					        var h = document.documentElement;
					        var b = document.body;
					        // 给window添加点击事件
					        w.onclick = function() {
					            console.log("我是window冒泡")
					        }
					        // 给document添加点击事件
					        d.onclick = function() {
					            console.log("我是document冒泡")
					        }
					        // 给html添加点击事件
					        h.onclick = function() {
					            console.log("我是html冒泡")
					        }
					        // 给body添加点击事件
					        b.onclick = function() {
					            console.log("我是body冒泡")
					        }
					        // 通过dom2级方式绑定事件到捕获阶段
					        w.addEventListener("click", function() {
					            console.log("我是window捕获")
					        }, true)
					        d.addEventListener("click", function() {
					            console.log("我是document捕获")
					        }, true)
					        h.addEventListener("click", function() {
					            console.log("我是html捕获")
					        }, true)
					        b.addEventListener("click", function() {
					            console.log("我是body捕获")
					        }, true)
					    </script>

运行结果如图:
DOM事件,捕获与冒泡处理,委托模式

阻止冒泡

阻止冒泡指的是当子元素的事件触发之后 不要让父元素的事件触发
事件流程分捕获与冒泡,通常我们只会往冒泡阶段添加事件。
有些时候,我们希望子元素执行事件,父元素不执行事件。

  • 高级浏览器中
    • e.stopPropagation()
  • IE浏览器中
    • e.cancelBubble = true;

阻止冒泡案例(让放大和移动可以不受对方影响)

功能分析:
1 当按住裁剪区域(亮的部分)并拖动时 可以左右 上下移动
按住: mousedown
拖动: mousemove
在mousemove事件中改变定位值
要求计算定位值的变化 = 鼠标的变化量(鼠标移动之后的位置减去鼠标按下的位置)
2 当按住右下角的点并拖动时 可以改变裁剪区域的大小
按住: mousedown
拖动: mousemove
在mousemove事件中改变宽高
要求计算宽高的变化 = 鼠标的变化量(鼠标移动之后的位置减去鼠标按下的位置)

					<style>
								*{margin: 0;padding: 0;}
								#box{width: 430px; height: 430px; margin: 50px auto; border: 1px solid #000; background: url(./images/small.jpg) no-repeat 0 0;position: relative;}
								.mask{width: 100%;height: 100%; position: absolute;top: 0;left: 0; background: rgba(65,65,65,.4);}
								#area{width:200px;height: 200px; position: absolute;top: 0; left: 0; background: url(./images/small.jpg) no-repeat 0 0;}
								#dot{width: 10px;height: 10px; position: absolute; right: -5px; bottom: -5px; border-radius: 50%; background: orange;}
				 </style>
				 <body>
						    <div id="box" class="a">
							        <div class="mask"></div>
							        <div id="area" class="a">
							            <div id="dot" class="a"></div>
							        </div>
						    </div>
							<script>
				        //  获取元素
				        var area = document.getElementById("area");
				        var dot = document.getElementById("dot");
				        // 添加按住事件 也就是mousedown
				        area.onmousedown = function(e) {
				            // 获取鼠标按下时的位置
				            var mouseX = e.clientX;
				            var mouseY = e.clientY;
				            // 获取鼠标按下时的定位值
				            var left = area.offsetLeft;
				            var top = area.offsetTop;
				            // 添加mousemove事件
				            document.onmousemove = function(e) {
				                // 获取鼠标现在的位置
				                var nowX = e.clientX;
				                var nowY = e.clientY;
				                // 计算变化量
				                var resultX = nowX - mouseX + left;
				                var resultY = nowY - mouseY + top;
				                area.style.left = resultX + "px";
				                area.style.top = resultY + "px";
				                area.style.backgroundPositionX = - resultX + "px";
				                area.style.backgroundPositionY = - resultY + "px";
				            }
				        }
				       document.onmouseup = function() {
				            document.onmousemove = null;
				        }
				        // 添加小圆点的按住事件 也就是onmousedown事件
				        dot.onmousedown = function(e) {
				            e.stopPropagation();
				            // 记住按下时的宽度高度
				            var width = area.clientWidth;
				            var height = area.clientHeight;
				            // 记住按下时的鼠标位置
				            var mouseX = e.clientX;
				            var mouseY = e.clientY;
				            // 添加移动事件
				            document.onmousemove = function(e) {
				                // 记住移动之后的位置
				                var nowX = e.clientX;
				                var nowY = e.clientY;
				                // 计算变化
				                var resultX = width + nowX - mouseX;
				                var resultY = height + nowY - mouseY;
				                area.style.width = resultX + "px";
				                area.style.height = resultY + "px";
				            }
				        }

运行结果: DOM事件,捕获与冒泡处理,委托模式

停止默认行为

在浏览器中,有许许多多的元素,有一些元素是具备默认行为的
比如:
a标签点击的时候会默认跳转页面
dom0级事件阻止a标签跳转,两种方法,1.return false (只适用用0级)
2 .e.preventDefault();

var a = document.getElementsByTagName("a")[0];
    a.onclick = function(e) {
        alert(123)
        // 如果不希望跳转 可以阻止默认行为 
        // 1 只适用于dom0级
        // return false;
        // 2 通过事件对象
        // e.preventDefault();
    }
   a.addEventListener("click", function(e) {
        // 只能用这种
         e.preventDefault();
        // dom2级中 return false无法阻止默认行为
        // return false;
    // })

submit按钮点击时会默认触发表单的submit事件

<form action='/a' method="get">
    用户名: <input type="text" name="username"  >
    密码: <input type="password" name="password"  >
    邮箱: <input type="text" name="email"  >
    提交: <button>如果我出现在form中并且没有指定type 则默认为submit</button>
</form>
<script>
    var inputs = document.getElementsByTagName("input");
    var button = document.getElementsByTagName("button")[0];
    button.onclick = function(e) {
        var flag = true;
        for (var i = 0; i < inputs.length; i++) {
            if (inputs[i].value === "") {
                flag = false;
                break;
            }
        }
        // flag代表是否有空值 为真表示没有空值 为假表示有空值
        if (!flag) {
            // 为假时会执行这里的代码 不要提交
            e.preventDefault();
        }
    }

委托模式

使用案例:

					<body>
					    <table>
					        <thead>
					            <tr>
					                <th>姓名</th>
					                <th>年龄</th>
					                <th>性别</th>
					                <th>操作</th>
					            </tr>
					        </thead>
					        <tbody>
					                <tr><td>张三</td><td>22</td><td>男</td><td>&times;</td></tr>
					                <tr><td>张三</td><td>22</td><td>男</td><td>&times;</td></tr>
					                <tr><td>张三</td><td>22</td><td>男</td><td>&times;</td></tr>
					                <tr><td>张三</td><td>22</td><td>男</td><td>&times;</td></tr>
					                <tr><td>张三</td><td>22</td><td>男</td><td>&times;</td></tr>
					                <tr><td>张三</td><td>22</td><td>男</td><td>&times;</td></tr>
					        </tbody>
					    </table>  
					    <button id="btn">点我增加数据</button>
					    <script>
					        // 获取tbody
					        var tbody = document.querySelector("tbody");
					        // 获取btn
					        var btn = document.querySelector("#btn");
					
					        btn.onclick = function() {
					            tbody.innerHTML += "<tr><td>张三</td><td>22</td><td>男</td><td>&times;</td></tr>"
					        }
					        // 使用委托模式
					        // 给tbody添加点击事件 
					        tbody.onclick = function(e) {
					            // 判定 如果是最后一个元素 我们就将当前的行移除
					            if (e.target === e.target.parentNode.lastChild) {
					                e.target.parentNode.remove();
					            }
					        }
					        // 使用方式: 将事件绑定给不会被移除的父元素 通过判定方式让代码只再符合某种条件时执行
					 </script>
					</body>