02 - JavaScript APIs - 02.高级事件

高级事件

注册事件 / 绑定事件

注册事件的两种方式:

  • 传统方式
    1.利用 on 开头的事件。btn.onclick = function() {}<button onclick="alert('hi~')"></button>
    2.特点:注册事件有唯一性
    -> 同一个元素同一个事件只能设置一个处理函数,最后注册的处理函数将会覆盖前面注册的处理函数
  • 方法监听
    1.addEventListener()
    2.W3C 标准,推荐方式
    3.IE9 前的 IE 不支持此方法,可用 attachEvent() 代替
    4.特点:同一个元素同一个事件可以注册多个监听器
    ->处理函数按注册顺序依次执行

addEventListener() 事件监听方式

  • eventTarget.addEventListener(type, listener[, useCapture])
    1.type:事件类型字符串,如 click,这里不带 on
    2.listener:事件处理函数,事件发生时,会调用该监听函数
    3.useCapture:可选参数,布尔值,默认是 false

attachEvent() 事件监听方式【IE8 及早期版本支持】

  • eventTarget.attachEvent(eventNameWithOn, callback)
    1.eventNameWithOn:事件类型字符串,如 onclick,这里要带 on
    2.callback:事件处理函数,当目标触发事件时回调函数被调用
    <body>
        <button>传统注册事件</button>
        <button>方法监听注册事件</button>
        <button>ie9 attachEvent</button>
        <script>
            var btns = document.querySelectorAll('button');
    
            btns[0].onclick = function() {
                alert('hi');
            }
            btns[0].onclick = function() {
                    alert('hao a u');
    	   	}
    
            btns[1].addEventListener('click', function() {
                alert(22);
            })
            btns[1].addEventListener('click', function() {
                    alert(33);
           	})
    		// ie9 以前的版本支持
            btns[2].attachEvent('onclick', function() {
                alert(11);
            })
        </script>
    </body>
    
    // 兼容性解决方案
    function addEventListener(element, eventName, fn) {
    	if (element.addEventListener) {
     		element.addEventListener(eventName, fn);
    	} else if (element.attachEvent) {
    		element.attachEvent('on' + eventName, fn);
     	} else {
     		// 相当于 element.onclick = fn;
     		element['on' + eventName] = fn;
    	}
    }
    

删除事件 / 解绑事件

传统注册方式

  • eventTarget.onclick = null;

方法监听注册方式

  • eventTarget.removeEventListener(type, listener[, useCapture]);【fn 调用不加小括号】
  • eventTarget.detachEvent(eventNameWithOn, callback);【fn 调用不加小括号】
    <head>
    	<style>
            div {
                width: 100px;
                height: 100px;
                background-color: pink;
            }
        </style>
    </head>
    
    <body>
        <div>1</div>
        <div>2</div>
        <div>3</div>
        <script>
            var divs = document.querySelectorAll('div');
            divs[0].onclick = function() {
                    alert(11);
                    divs[0].onclick = null;
                }
    
            divs[1].addEventListener('click', fn) // fn 不需要调用加小括号
            function fn() {
                alert(22);
                divs[1].removeEventListener('click', fn);
            }
    
            divs[2].attachEvent('onclick', fn1);
            function fn1() {
                alert(33);
                divs[2].detachEvent('onclick', fn1);
            }
        </script>
    </body>
    
    // 兼容性解决方案
    function removeEventListener(element, eventName, fn) {
    	if (element.removeEventListener) {
     		element.removeEventListener(eventName, fn);
     	} else if (element.detachEvent) {
     		element.detachEvent('on' + eventName, fn);
     	} else {
     		element['on' + eventName] = null;
    	} 
    }
    

DOM 事件流

  • 事件流:描述的是从页面中接收事件的顺序
  • DOM 事件流:事件发生时在元素节点间按照特定顺序传播的过程
  • DOM 事件流分为 3 个阶段:捕获阶段 -> 当前目标阶段 -> 冒泡阶段
    在这里插入图片描述
    注:
    ①事件冒泡:IE 最早提出。事件开始时由最具体的元素接收,然后逐级向上传播到到 DOM 最顶层节点的过程
    ②事件捕获:网景最早提出,由 DOM 最顶层节点开始,然后逐级向下传播到到最具体的元素接收的过程
  • JS 代码只能执行捕获 或 冒泡其中的一个阶段
  • addEventListener(type, listener[, useCapture])
    ①useCapture 为 true,在事件捕获阶段调用事件处理程序;
    ②useCapture 为 false(不写就默认是 false),在事件冒泡阶段调用事件处理程序
  • 实际开发中更关注事件冒泡【事件冒泡有时带来麻烦,有时带来巧妙】
  • onclickattachEvent 只能得到冒泡阶段
  • onbluronfocusonmouseenteronmouseleave 只能得到捕获阶段
  • 示例
    <head>
        <style>
            .father {
                overflow: hidden;
                width: 300px;
                height: 300px;
                margin: 100px auto;
                background-color: pink;
                text-align: center;
            }
            .son {
                width: 200px;
                height: 200px;
                margin: 50px;
                background-color: purple;
                line-height: 200px;
                color: #fff;
            }
        </style>
    </head>
    
    <body>
        <div class="father">
            <div class="son">son盒子</div>
        </div>
        <script>
            // var son = document.querySelector('.son');
            // son.addEventListener('click', function() {  // father -> son
            //     alert('son');
            // }, true);
            // var father = document.querySelector('.father');
            // father.addEventListener('click', function() {
            //     alert('father');
            // }, true);
            
            document.addEventListener('click', function() {  // son -> father -> document
                alert('document');
            })
            var father = document.querySelector('.father');
            father.addEventListener('click', function() {
                alert('father');
            }, false);
            var son = document.querySelector('.son');
            son.addEventListener('click', function() {
                alert('son');
            }, false);
        </script>
    </body>
    

事件对象

概述

  • eventTarget.onclick = function(event) {}
    eventTarget.addEventListener('click', function(event) {})
    event 代表事件的状态,如键盘按键的状态、鼠标按钮的状态、鼠标位置。即事件发生后,事件相关的一系列信息数据的集合,event 有很多属性和方法

适用语法

  • eventTarget.onclick = function(event) {}【event 可以写成 e 或 evt】【event 不需传实参,系统帮我们设定为事件对象。注册事件时,event 会被系统自动创建,并依次传递给事件监听器】
  • eventTarget.addEventListener('click', function(event) {})【event 可以写成 e 或 evt】【event 不需传实参,系统帮我们设定为事件对象。注册事件时,event 会被系统自动创建,并依次传递给事件监听器】
  • 示例:
    <head>
        <style>
            div {
                width: 100px;
                height: 100px;
                background-color: pink;
            }
        </style>
    </head>
    
    <body>
        <div>123</div>
        <script>
            var div = document.querySelector('div');
            div.onclick = function(e) {
           		e = e || window.event;
       			console.log(e);
    		}
         	div.addEventListener('click', function(e) {
      			console.log(e);
            })
        </script>
    </body>
    

兼容性方案

  • 事件对象本身的获取存在兼容问题:
    1.标准浏览器中是浏览器给方法传递的参数,只需定义形参 e 就可以获取到
    2.在 IE6~8 中,浏览器不会给方法传递参数,若需要,要到 window.event 中获取查找
  • 解决方案:e = e || window.event【见 适用语法 示例】

常见属性和方法

  • e.type【返回事件的类型,如 click,不带 on】
  • e.target【返回触发事件的对象】【标准】
    currentTarget【与e.target相似】【ie678不认识】
    this【返回绑定事件的对象,即函数的调用者】
    <body>
        <div>123</div>
        <ul>
            <li>abc</li>
            <li>abc</li>
            <li>abc</li>
        </ul>
    	<script>
            var ul = document.querySelector('ul');
            ul.addEventListener('click', function(e) {
      			console.log(this);  // 指向 ul
    	      	console.log(e.currentTarget);
                console.log(e.target);  // 点击的是 li,则 e.target 指向的就是 li
    		})
            
            // 了解兼容性
            // div.onclick = function(e) {
            //     e = e || window.event;
            //     var target = e.target || e.srcElement;
            //     console.log(target);
            // }
        </script>
    </body>
    
  • e.srcElement【返回触发事件的对象】【非标准,ie6-8 使用】
  • e.stopPropagation()【阻止冒泡】【标准】
  • e.cancelBubble【阻止冒泡】【非标准,ie6-8 使用】
  • e.preventDefault()【阻止默认事件】【标准】
  • e.returnValue【阻止默认事件】【非标准,ie6-8使用,如禁止链接跳转】

阻止事件冒泡

两种方式

  • e.stopPropagation()【标准】
  • e.cancelBubble = true;【非标准】
  • 示例
    <body>
        <div>123</div>
        <a href="http://www.baidu.com">百度</a>
        <form action="http://www.baidu.com">
        	<input type="submit" value="提交" name="sub">
        </form>
        <script>
            var div = document.querySelector('div');
            div.addEventListener('click', fn);
            div.addEventListener('mouseover', fn);
            div.addEventListener('mouseout', fn);
    
            function fn(e) {
                console.log(e.type);
            }
    
            var a = document.querySelector('a');
            a.addEventListener('click', function(e) {
                    e.preventDefault();
            })
    
            a.onclick = function(e) {
                // 普通浏览器 e.preventDefault(); 方法
                // e.preventDefault();
                
                // 低版本浏览器 ie678 returnValue 属性
                // e.returnValue;
                
                // 可利用return false也能阻止默认行为
                // 没有兼容性问题
                // 特点:return 后的代码不执行了,且只限于传统注册方式
                return false;
                alert(11);
            }
        </script>
    </body>
    
    // 兼容性解决方案
    if(e && e.stopPropagation){
    	e.stopPropagation();
    }else{
    	window.event.cancelBubble = true;
    }
    
    // 阻止冒泡
    <head>
        <style>
            .father {
                overflow: hidden;
                width: 300px;
                height: 300px;
                margin: 100px auto;
                background-color: pink;
                text-align: center;
            }
            .son {
                width: 200px;
                height: 200px;
                margin: 50px;
                background-color: purple;
                line-height: 200px;
                color: #fff;
            }
        </style>
    </head>
    
    <body>
        <div class="father">
            <div class="son">son儿子</div>
        </div>
        <script>
            var son = document.querySelector('.son');
            son.addEventListener('click', function(e) {
                alert('son');
                e.stopPropagation();
                e.cancelBubble = true;
            }, false);
    
            var father = document.querySelector('.father');
            father.addEventListener('click', function() {  // father 未阻止
                alert('father');
            }, false);
            
            document.addEventListener('click', function() {
                alert('document');
            })
        </script>
    </body>
    

事件委托(代理、委派)

事件委托 / 事件代理【jQuery 中称为事件委派】

  • 不是每个子节点单独设置事件监听器,而是事件监听器设置在其父节点上,然后利用冒泡原理影响设置每个子节点
    如,给 ul 注册点击事件,然后利用事件对象的 target 找到当前点击的 li,因为点击 li,事件会冒泡到 ul 上,ul 有注册事件,就会触发事件监听器
  • 只操作了一次 DOM ,提高了程序的性能
  • 示例
    <body>
        <ul>
            <li>知否知否,点我应有弹框在手!</li>
            <li>知否知否,点我应有弹框在手!</li>
            <li>知否知否,点我应有弹框在手!</li>
            <li>知否知否,点我应有弹框在手!</li>
            <li>知否知否,点我应有弹框在手!</li>
        </ul>
        <script>
            var ul = document.querySelector('ul');
            ul.addEventListener('click', function(e) {
                e.target.style.backgroundColor = 'pink';
            })
        </script>
    </body>
    

常用的鼠标事件

  • onclickonmouseoveronmouseoutonfocusonbluronmousemoveonmouseuponmousedown
  • contextmenu【禁用右键菜单】、selectstart【禁止鼠标选中】
    <body>
        我是一段不愿意分享的文字
        <script>
            document.addEventListener('contextmenu', function(e) {  // 禁用右键菜单
                    e.preventDefault();
            })
            document.addEventListener('selectstart', function(e) {  // 禁止选中文字
                e.preventDefault();
            })
        </script>
    </body>
    
  • e.clientXe.clientY【返回鼠标相对于浏览器窗口可视区的XY坐标】
    e.pageXe.pageY【返回鼠标相对于文档页面的XY坐标】【IE9+ 支持】
    e.screenXe.screenY【返回鼠标相对于电脑屏幕的XY坐标】
    <head>
        <style>
            body {
                height: 3000px;
            }
        </style>
    </head>
    
    <body>
        <script>
            document.addEventListener('click', function(e) {
                console.log(e.clientX);
                console.log(e.clientY);
                console.log('---------------------');
    
                console.log(e.pageX);
                console.log(e.pageY);
                console.log('---------------------');
    
                console.log(e.screenX);
                console.log(e.screenY);
            })
        </script>
    </body>
    
  • 示例
    // 跟随鼠标的天使
    <head>
        <style>
            img {
                position: absolute;  // 图片要移动距离,且不占位置,使用绝对定位即可
                top: 2px;
            }
        </style>
    </head>
    
    <body>
        <img src="images/angel.gif" alt="">
        <script>
            var pic = document.querySelector('img');
            document.addEventListener('mousemove', function(e) {
                var x = e.pageX;
                var y = e.pageY;
                console.log('x坐标是' + x, 'y坐标是' + y);
                
                pic.style.left = x - 50 + 'px';  // 一定要加 px 单位
                pic.style.top = y - 40 + 'px';
            });
        </script>
    </body>
    

常用的键盘事件

  • onkeyup【某个键盘按键被松开时触发】【不区分字母大小写】
  • onkeydown【某个键盘按键被按下时触发】【不区分字母大小写】
  • onkeypress【某个键盘按键被按下时触发】【不能识别功能键,如 ctrl、shift、箭头】【区分字母大小写】
    三者的执行顺序:keydown -> keypress -> keyup
    <body>
        <script>
          	document.onkeyup = function() {
            	console.log('我弹起了');
    		}
    
            document.addEventListener('keypress', function() {
            	console.log('我按下了press');
            })
    
            document.addEventListener('keydown', function() {
            	console.log('我按下了down');
            })
        </script>
    </body>
    
  • keyCode【返回该键的 ASCII 值】【区分字母大小写】
    <body>
        <script>
            document.addEventListener('keyup', function(e) {
                // console.log(e);
                console.log('up:' + e.keyCode);
                if (e.keyCode === 65) {
                    alert('您按下的a键');
                } else {
                    alert('您没有按下a键')
                }
            })
            document.addEventListener('keypress', function(e) {
                // console.log(e);
                console.log('press:' + e.keyCode);
            })
        </script>
    </body>
    
  • 示例
    // 模拟京东按键输入内容
    <body>
        <input type="text">
        <script>
            var search = document.querySelector('input');
            // keydown、keypress 事件触发时,文字还未落入文本框中
            // keyup 事件触发时,文字已落入文本框中了
            document.addEventListener('keyup', function(e) {  // 若为 keydown,在获得焦点时还会输入 s
                if (e.keyCode === 83) {
                    search.focus();
                }
            })
        </script>
    </body>
    
    // 模拟京东快递单号查询
    <head>
        <style>
            * {
                margin: 0;
                padding: 0;
            }
            .search {
                position: relative;
                width: 178px;
                margin: 100px;
            }
            .con {
                display: none;
                position: absolute;
                top: -40px;
                width: 171px;
                border: 1px solid rgba(0, 0, 0, .2);
                box-shadow: 0 2px 4px rgba(0, 0, 0, .2);
                padding: 5px 0;
                font-size: 18px;
                line-height: 20px;
                color: #333;
            }
            .con::before {
                content: '';
                width: 0;
                height: 0;
                position: absolute;
                top: 28px;
                left: 18px;
                border: 8px solid #000;
                border-style: solid dashed dashed;
                border-color: #fff transparent transparent;
            }
        </style>
    </head>
    
    <body>
        <div class="search">
            <div class="con">123</div>
            <input type="text" placeholder="请输入您的快递单号" class="jd">
        </div>
        <script>
            var con = document.querySelector('.con');
            var jd_input = document.querySelector('.jd');
            jd_input.addEventListener('keyup', function() {
            	if (this.value == '') {
                	con.style.display = 'none';
             	} else {
                  	con.style.display = 'block';
                 	con.innerText = this.value;
            	}
        	})
    
            jd_input.addEventListener('blur', function() {
            	con.style.display = 'none';
            })
            jd_input.addEventListener('focus', function() {
                if (this.value !== '') {
                	con.style.display = 'block';
                }
            })
        </script>
    </body>
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值