DOM -- 重新认识事件

版权声明:本文为博主原创文章,若文章中有错误请联系博主改正,请不要恶意留言(不喜欢请绕道)。欢迎大家转载,转载时请注明原文地址:https://blog.csdn.net/qq_37674616/article/details/82470350

目录

事件

事件流

冒泡事件流

捕获事件流

DOM事件流

事件处理程序

DOM0级事件处理程序

 DOM2级事件处理程序

非IE8版本以下

扫描二维码关注公众号,回复: 3077993 查看本文章

 IE8版本以下

对于事件程序兼容处理

事件对象

非IE8以下

IE8以下

浏览器兼容处理

事件委托

事件类型

UI事件

 焦点事件

鼠标事件

坐标属性

滚动事件

文本事件

键盘事件


事件

事件,就是文档或浏览器窗口中发生的一些特定交互瞬间
事件的三要素

事件目标

事件处理程序

事件对象
例如 btn.function(event){} 对该用事件来代码分析,则 btn为事件目标 ,事件处理程序为 function函数,  事件对象 event


事件流

事件流描述的是从页面中接收事件的顺序。事件流可分为冒泡事件流和捕获事件流。


冒泡事件流

该事件流又称IE事件流,该事件流是从内向外传播(即逐级向上传播)


下图此时事件会按照如下顺序传播:
                handle1 -->handle2 -->handle3 -->handle4

				<html>
					<head>
					 	<title></title>
					</head>
					<body>
					 	<div id="myDiv">Click Me</div>
					</body>
				</html> 
				<script>
					div.onclick=handle1;
					body.onclick=handle2;
					html.onclick=handle3;
					document.onclick=handle4;
					function handle1(){}
					function handle2(){}
					....
				</script>

捕获事件流

该事件流又称NetScape Communicator(网景).
思想:是不太具体的节点应该更早接受到事件,而最具体的节点应该最后接受到事件。即事件是从外到内传播

此时事件会按照如下顺序传播:
                handle4 -->handle3 -->handle2 -->handle1

				<html>
					<head>
					 	<title></title>
					</head>
					<body>
					 	<div id="myDiv">Click Me</div>
					</body>
				</html> 
				<script>
					div.onclick=handle1;
					body.onclick=handle2;
					html.onclick=handle3;
					document.onclick=handle4;
					function handle1(){}
					function handle2(){}
					....
				</script>

DOM事件流

该事件分三个阶段:事件捕获阶段、处于目标阶段和事件冒泡阶段。首先从事件捕获阶段开始,然后到实际的目标接受事件,最后为事件冒泡阶段。

事件处理程序

DOM0级事件处理程序

该处理程序不存在兼容性问题。

 缺点:

         1.是要等待html页面加载完毕后才能操作

         2.只能添加一个事件处理程序(会覆盖)
            形式:

                var btn=document.getElementById('myBtn');
                btn.onclick=function(){
                    console.log('我不会被执行');
                }
                btn.onclick=function(){
                    console.log(this.id); //"myBtn"
                }
                    //删除绑定
                    btn.onclick=null;

 **:DOM0级中的this指向调用者即事件目标
     

 DOM2级事件处理程序

该事件处理程序存在兼容性问题,一般分为IE8版以下和非IE8版本以下

优点:可以添加多个事件处理函数(执行顺序有差异的区别对待)


非IE8版本以下

定义两个方法用于处理指定和删除事件程序:addEventListener()和removeEventListener().

addEventListener(type,handle,boolean)
                    参数
                        type:要处理事件的事件名
                        handle:事件处理的函数
                        boolean:true/false 
true表示在捕获阶段调用事件处理程序,false表示在冒泡阶段调用处理程序。默认为false

 removeEventListener(type,handle,boolean)
                    参数
                        type:要处理事件的事件名
                        handle:事件处理的函数
                        boolean:true/false 
true表示在捕获阶段调用事件处理程序,false表示在冒泡阶段调用处理程序。默认为false
                事件执行顺序

                    var btn=document.getElementById('myBtn');
                    btn.addEventListener('click',function(){
                        console.log(this.id);
                    });
                    btn.addEventListener('click',function(){
                        console.log("hello");
                    });

  **:从上到下执行顺序执行即先打印ID然后"hello";

匿名函数不能解绑事件

                    var btn=docuemnt.getElementById('myBtn');
                    btn.addEventListener('click',function(){
                        console.log(this.id);
                    });
                    btn.removeEventListener('click',function(){ //没有用!
                        console.log('事件被移除'); 
                    });

**:因为两个匿名函数在堆内存中的地址不一样所以无法解除绑定。因此我们要将函数的引用传入给事件处理函数,这样才能解除绑定。

                    function handle(){
                        console.log(this.id);
                    }
                var btn=docuemnt.getElementById('myBtn');
                    btn.addEventListener('click',handle);
                    btn.removeEventListener('click',handle);


 IE8版本以下

对以该版本对于事件处理程序提供:attachEvent()、detachEvent()。这两个方法接受相同的两个参数:事件处理程序名称和事件处理程序函数。

                var btn=document.getElementById('MyBtn');
                btn.attachEvent('onclick',function(){
                    console.log(this===window); //true
                });

**:IE8以下用DOM2级绑定事件this指向window

事件执行顺序

                    btn.attachEvent('onclick',function(){
                        console.log('click'); 
                    });
                    btn.attachEvent('onclick',function(){ //先被执行
                        console.log("hello"); 
                    });

**:事件处理是以相反顺序执行即先打印"hello"然后打印"click"。
解除绑定

同样如果函数是以匿名函数写入则不能解除绑定。

                    var btn=document.getElementById('MyBtn');
                    btn.attachEvent('onclick',handle);
                    //解除绑定
                    btn.detachEvent("onclick",handle);


对于事件程序兼容处理

<script>
    var util = {
        //绑定事件
        band: function(element, type, handle) {
            if (element.addEventListener) {
                element.addEventListener(type, handle, false);
            } else if (element.attachEvent) {
                //IE8以下版本
                element.attachEvent("on" + type, handle);
            } else {
                //兜底
                element['on' + type] = handle;
            }
        },
        //解除绑定
        unband: function(element, type, handle) {
            if (element.removeEventListener) {
                element.removeEventListener(type, handle, false);
            } else if (element.detachEvent) {
                element.detachEvent("on" + type, handle);
            } else {
                element["on" + type] = null;
            }
        }
    };
    var btn = document.getElementById('myBtn');

    util.band(btn, 'click', handle);

    function handle() {
        console.log(this.id);
    }
</script>

事件对象

非IE8以下

属性

currentTarget       表示当前正在处理事件的那个元素

target                  事件的目标

type                   被触发的事件类型

detail                 与事件相关的细节信息

eventPhase       调用事件处理程序的阶段:1 表示捕获阶段,2 表示"处于目标" 3 表示冒泡阶段

方法

preventDefault()

         只读属性。取消事件的默认行为
示例

我们可以阻止a链接的默认行为(即点击后会导航到指定url)

                    var link=document.getElementById('myLink');
                    link.onclick=function(event){
                        event.preventDefault();
                    }

stopPropagation()

       只读属性。取消冒泡事件或捕获
示例

                    <html>
                        <head>
                             <title></title>
                        </head>
                        <body>
                             <div id="myDiv">Click Me</div>
                        </body>
                    </html>
            <script>
                    div.onclick=handle1;
                    body.onclick=handle2;
                    function handle1(event){
                            console.log('div');
                            //阻止,冒泡事件的传播
                            event.stopPagation();
                      }
                    function handle2(){
                            console.log('body'); //不会打印
						}
            </script>

IE8以下

事件对象的不同

 在DOM0级事件处理程序中

event对象作为window对象中的一个属性存在

                    var btn=document.getElementById('myBtn');
                    btn.onclick=function(){
                        var event=window.event;
                        console.log(event.type);
                    }

在DOM2级事件处理程序中

                    event对象作为参数被传入事件处理程序函数。
                    var btn=document.getElementById('myBtn');
                    btn.attachEvent("onclick",function(event){
                        console.log(event.type);
                    });

 属性

srcElement
                    只读属性。事件的目标(与target属性相同)

type
                    只读属性。被触发的事件类型

 方法

 cancelBubble(true/false)

          可读可写。默认值为false,true取消事件冒泡
示例

<html>
	<head>
		<title></title>
	</head>
	<body>
		<div id="myDiv">Click Me</div>

	<script>
		div.onclick=handle1;
		body.onclick=handle2;
		function handle1(){
			console.log('div');
			//阻止,冒泡事件的传播
			window.event.cancelBubble=true;
		}
		function handle2(){
			console.log('body'); //不会打印
		}
	</script>
	</body>
</html> 

 returnValue(true/false)

          可读可写。默认是true,设置为false表示取消事件的默认行为。

                    var link=document.getElementById('myLink');
                    link.onclick=function(){
                        window.event.returnValue=false;
                    }

浏览器兼容处理

<body>
    <button id="myBtn">点击我</button>
    <script>
    var util = {
        //获取对象事件
        getEvent: function(event) {
            return event ? event : window.event;
        },
        //获取事件源
        getTarget: function(event) {
            return event.target || event.srcElement;
        },
        //阻止默认行为	
        preventDefault: function(event) {
            if (event.preventDefault) {
                event.preventDefault();
            } else {
                event.returnValue = false;
            }
        },
        //阻止冒泡或捕获
        stopPropagation: function(event) {
            if (event.stopPropagation) {
                event.stopPropagation();
            } else {
                event.canceBubble = true;
            }
        }
    };
    var btn = document.getElementById('myBtn');
    btn.onclick = function(event) {
        console.log('btn');
        //获取事件对象
        event = util.getEvent(event);
        util.stopPropagation(event);
    }
    document.body.onclick = function() {
        console.log('body'); //不会打印
    }
    </script>
</body>

事件委托

事件委托就是利用事件冒泡,只指定一个事件处理程序,就可以管理某一类型的所有事件。

 案例:当鼠标移入li时给给li添加背景移除时背景移除。

<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <title>鼠标移入移出背景变化</title>
    <link rel="stylesheet" href="">
    <style>
    #list {
        padding: 0;
        list-style: none;
        border: 1px solid black;
        overflow: hidden;
    }

    li {
        margin: 10px;
        width: 100px;
        height: 100px;
        border: 1px solid black;
        display: inline-block;
    }
    </style>
    <script>
    var util = {
        getEvent: function(event) {
            return event ? event : window.event;
        },
        getTarget: function(event) {
            return event.target ? event.target : event.srcElement;
        }
    }
    window.onload = function() {
        var ul = document.getElementById('list');
        //鼠标移入事件
        ul.onmouseover = function(event) {
            //获取事件对象
            var event = util.getEvent(event);
                //获取事件源
            var target = util.getTarget(event);
            if (target.nodeName == "LI") {
                  //改变选中的li背景
                target.style.background = 'orange';
            }
        }
        //鼠标移出事件
        ul.onmouseout = function() {
            var event = util.getEvent(event);
            var target = util.getTarget(event);
            if (target.nodeName == "LI") {
                target.style.background = '';
            }
        }
    }
    </script>
</head>

<body>
    <ul id="list">
        <li></li>
        <li></li>
        <li></li>
    </ul>
</body>

</html>

**:如果这个案例我们给li绑定鼠标事件,就需要给所有li绑定那么页面会多次渲染就算我们不点击也会这样做。而且如果我们给ul追加子节点时该要加鼠标事件。这些问题事件委托就能帮我们很好的解决。

事件类型

UI事件

该事件指的是不一定与用户操作有关的事件

load

当页面完全加载后在window上面触发,当所有框架都加载完时在框架上触发,当图片加载完毕时在<img>元素上触发,当嵌入的内容加载完毕时在<object>元素上面触发

unload

当页面完全卸载后在window上面触发.当所有框架都卸载后在框架上面触发

 select

 当用户选择文本框中的一或多个字符时触发

 resize

当窗口或框架的大小变化时在window或框架上面触发

scroll

当页面滚动带滚动条的元素中的内容时,在该元素上面触发。

 焦点事件

焦点事件会在页面元素获取或失去焦点时触发。

 blur

在元素失去焦点时触发。这个事件不会冒泡

focus

在元素获取焦点是触发。这个事件不会冒泡

 focusin

在元素获取焦点时触发。这个事件与focus等价但会冒泡

focusout

在元素失去焦点时触发。这个事件与blur等价。

鼠标事件

click

用户单击鼠标按键或按下回车键时触发。

dbclick

在用户双击主鼠标按钮时触发

mousedown

在用户按下任意鼠标按钮时触发。

mouseup

在用户抬起鼠标按钮时触发

mouseenter

在鼠标从元素外部首次进入到元素之内时触发,这个事件不会冒泡,而且在光标移动到后代元素时不会触发

mouseleave

在位于元素上的鼠标光标移动到元素范围之外时触发。这个事件不会冒泡,而且在光标移动到后代元素上不会触发

mousemove

当鼠标指针在元素内部移动时重复触发,支持冒泡

 mousemove

当鼠标指针位于一个元素上方,然后移动出该元素时触发。支持冒泡

 mouseover

当鼠标位指针位于一个元素外部,然后用户将其首次移入另一个元素边界之内时触发。支持冒泡

坐标属性

视口坐标
                    clientX
                    clientY

页面坐标
                    pageX
                    pageY

屏幕坐标
                    screenX
                    screenY

**:当页面不滚动时视口坐标与页面坐标相等

滚动事件

mousewheel

该事件IE、Opera、Chrome和Safari都实现了。

wheelDelta

该属性可以检测用户鼠标是前滚动还是后滚动。wheelDelta是120的倍数.当用户向前滚动时是正120的倍数、向后滚动时是-120的倍数。

 **:如果在Opera9.5版本之前,wheelDelta的值的正负号是颠倒的。

 DOMMouseScroll

 该事件只有火狐支持,而且不支持DOM0级绑定该属性。在滚动信息中保存在detail属性中。当鼠标向前滚动时,这个属性的值是-3的倍数。向后滚动时是3的倍数。

滚动事件的兼容

我们将前面事件兼容的工具方法整理到一起:

var util = {
    //绑定事件的方法
    band: function(ele, type, handle) {
        //元素  类型  事件函数 
        if (ele.addEventListener) {
            ele.addEventListener(type, handle);
        } else if (ele.attachEvent) {
            ele.attachEvent('on' + type, handle);
        } else {
            ele['on' + type] = handle;
        }

    },
    //解绑
    unband: function(ele, type, handle) {
        if (ele.removeEventListener) {
            ele.removeEventListener(type, handle);
        } else if (ele.detachEvent) {
            ele.detachEvent('on' + type, handle);
        } else {
            ele['on' + type] = null;
        }
    },
    //event对象
    getEvent: function(event) {
        return event = event ? event : window.event;
    },
    //冒泡
    stopPropagation: function(event) {
        if (event.stopPropagation) {
            event.stopPropagation();
        } else {
            //IE及以下阻止冒泡
            event.cancelBubble = false;
        }
    },
    //阻止默认
    preventDefault: function(event) {
        if (event.preventDefault) {
            event.preventDefault();
        } else {
            event.returnValue = false;
        }
    },
    //事件源
    getTarget: function(event) {
        return event.target ? event.target : event.srcElement;
    },
    //获取滚动值
    getWheelDelta: function(event) {
        if (event.wheelDelta) {
            return (client.engine.opera && client.engine.opera < 9.5 ? -event.wheelDelta : event.wheelDelta);
        } else {
            return -event.detail * 40;
        }
    }
}

下面我们来写测试上面鼠标滚动的兼容性:

 <script>
    var client = function() {
        var engine = {
            //呈现引擎
            ie: 0,
            gecko: 0,
            webkit: 0,
            khtml: 0,
            opera: 0,
            //具体版本号
            ver: null
        };
        return {
            engine: engine
        };
    }();  
    util.band(document, 'mousewheel', scroll);
    util.band(document, 'DOMMouseScroll', scroll);

    function scroll(event) {
        var event = util.getEvent(event);
        if (util.getWheelDelta(event) > 0) {
            console.log('向前走');
        } else {
            console.log('向后走');
        }
    }
</script>

文本事件

 textInput

当用户在可编辑区域中输入字符是,就会触发这个事件。支持该属性的浏览器有IE9+、Safari和Chrome(测试只时IE11不支持该属性)

测试:

	<script>
		var input=document.getElementById('myText');
		util.band(input,'textInput',function(event){
			var event=util.getEvent(event);
				alert(event.data);
		});
	</script>

**:上面的代码都用到了工具方法请先导入该工具对象。

键盘事件

 keydown

当用户按下键盘上的任意键时触发,而且如果按住不放会重复触发此事件。

 keypress

当用户按下键盘上的字符键时触发,而且如果按住不放的话会重复触发

keyup

当用户释放键盘上的键时触发

 键码

在发生keydown和keyup事件时,event对象的KeyCode属性中会包含一个代码与键盘上一个特定的键对应

猜你喜欢

转载自blog.csdn.net/qq_37674616/article/details/82470350