13 js08 事件
事件:交互体验的核心,div.onclick = function(){};// "="号左边就是事件了,右边是触发事件执行的函数;所谓的绑定事件,并非是创建事件,dom元素本来就有事件,我们只是绑定了执行函数而已;【当页面全部加载完成后,程序执行从同步脚本执行阶段,转化为事件驱动阶段】
1、绑定事件处理函数的三种方式:
(1).div.onclick = function(){ this.style.backgroundColor='red';} 等同于在行内样式中添加, <div style="width:100px" onclick="console.log('a')"></div>//行内样式中直接写函数执行语句,不需要写function(){};//以上这种方式被称为“句柄绑定”的方式; -------->>>其兼容性很好,缺点:一个对象的一个事件只能绑定一个处理函数(绑定多个函数会出现覆盖现象);
(2).div.addEventListener(事件类型、处理函数、false); div.addEventListener('click',function(){},false);其可以给一个对象的一个事件绑定多个处理函数,并且按照绑定的顺序执行;IE9以下不兼容;
[1].下式绑定的函数是引用值,显然点击触发的是两个不同的函数,结果:点击一次输出两个a;
[2]. 下式绑定的函数引用,其是同一个函数,结果:点击一次输出一个b;
(3).IE9独有:div.attachEvent('on'+事件类型,处理函数);一个对象的一个事件绑定多个处理函数, 但其不同于div.addEventListener(); 即使是[2].式其也可以执行多次,结构很松散;
事件中的this指向问题:
------>>>封装兼容性的绑定函数方法:
解除事件绑定:使用场景还是蛮广的,有的事件绑定只需要进行一次就OK,绑定后需要解除绑定;(封装解除事件绑定的函数应用场景不大)
事件中形成的闭包现象:(开发中经常遇到,但不容易想到)
例:点击每个li,输出序号;
[注:事件一旦出现在循环当中,重点考虑函数与for循环是否形成闭包,若出现闭包,使用立即执行函数解决]
2、事件处理模型:冒泡、捕获;[事件处理方式,其也是特殊现象] 【聚焦点:结构上嵌套,同一事件类型】
(1).事件冒泡:结构上(非视觉上)嵌套关系的元素,会存在事件冒泡,同一事件,子元素冒泡向父元素;(自底向上) 【每个浏览器都支持】三种事件绑定处理函数都OK;
(2).事件捕获:结构上(非视觉上)嵌套关系的元素,会存在事件捕获的功能,即同一事件,自父元素捕获至子元素(事件源对象);(自顶向下) 【早期只有谷歌支持,目前火狐和opera高版本支持低版本没有(高版本的几乎都涉及谷歌的webkit内核),IE不支持捕获事件类型】div.addEventListener('click',function(){}, true); 只要把第三个参数由false变为true即可;
【其也可认为是捕获:div.setCapture();//仅在IE浏览器好使,dom元素会将页面中所有的事件硬捕获到自己身上,常与div.releaseCapture();配套使用//捕获后需要释放,因为其对其他事件有坏处】
(3).先捕获,后冒泡:嵌套关系的父子元素才谈这两个现象,一个对象一个事件类型绑定的一个执行函数只能遵循一个事件处理模型,要不冒泡、要不捕获;但一个对象一个事件可以绑定多个执行函数,若是绑定两个执行函数,一个冒泡、一个捕获,则先发生捕获、后冒泡;涉及多个处理函数,只能用第二种了;
顺序:点击黄色方块-->>红色方块捕获-->>绿色方块捕获-->>黄色方块执行-->>黄色方块执行-->>冒泡向绿色方块-->>冒泡向红色方块;(黄色方块执行顺序就是书写的事件执行顺序)
补充:并非所有事件都会冒泡:focus,blur,change,submit,reset,select等事件不冒泡;【冒泡/捕获聚焦点是同一事件类型,多为点击事件类型】
------->>>>>取消冒泡:冒泡是事件处理方式,有时候不需要这类现象的发生;应用场景:document是所有dom元素的父级,若是给document绑定事件,其他dom元素绑定同类事件,则会发生冒泡,必须取消冒泡的影响; [1].event.stopPropagation();// w3c标准,ie9以下不兼容; [2].IE9以下:event.cancelBubble = true;//目前chrome也已经实现
----->>>>>封装兼容性函数:【图示这种if条件判断语句不能使用三目运算符,三目聚焦点是返回值,var a; if(){ a = xxx}else{ a = xxx},这种方式可以使用三目】
3、阻止事件默认行为:(应用场景很广泛)[有默认行为的事件类型并不多] [手机、电脑、平板等系统内部自带很多默认事件,例如鼠标右击弹出菜单便是一个默认事件,可以阻止其的发生;常见的默认事件:表单提交、a标签跳转、右键菜单等等]
(1).return false;// 只能用于事件句柄中div.onclick; 其他事件绑定函数中不能使用;document.oncontextmenu = function(){ console.log('a'); ruturn false;}
(2).event.preventDefault();// w3c标准,IE9以下不兼容;
(3).event.returnValue = false;// IE;
封装兼容性函数:(1)return false;//不好实现, 同理return f(n);函数也不好实现;封装函数足够用了
补充: a标签有默认行为:<a href="#"></a>跳转到“#”并刷新页面; // 如果在底部进行a标签的跳转,页面会弹回顶部,开发中我们常使用a标签当作按钮使用,需要阻止默认行为; [1].常规:event.preventDefault();或者使用兼容性封装函数也OK; [2].<a href="javascript:void()">demo</a>;使用协议协定符;<a href="javascript:alert('a')"></a> href=“js代码”,点击便会去执行js代码;同样使用<a href="javascript: void()">demo</a>,void()等同于是返回值,void(false) ===>>> return false;
4、事件对象event:触发事件后的所有信息都封装在event对象中(反映当前事件发生时的一系列状态和信息),浏览器默认把event事件对象传给形参,IE浏览器其会把event事件对象传window.event上,兼容性写法:div.onclick = function(e){var event = e || window.event}
[event.clientX/clientY: 事件触发时鼠标的x,y坐标,等同于pageX/pageY; clientWidth/Height可视区]
【1.尽量使用形参;2.后续event事件对象的使用可以巧妙解决很多问题】
5、事件源对象:确认是谁触发的事件(由于有事件冒泡模型,嵌套元素都可以触发事件执行函数,但并不清楚是那个元素触发);根据event事件对象来确认事件源对象,event.target;火狐只有这个,event.srcElement IE只有这个,chrome两者都有,兼容性写法:
6、事件委托(事件代理):利用事件冒泡、事件源对象进行处理;(巧妙使用,节省性能)
例:给每个li绑定事件,点击触发后输出标签内容;
常规写法:虽然可以实现功能,但若是动态增加<li>个数、<li>总数过多,性能和灵活性便会变差;使用“事件委托”,绑定<ul>,利用事件冒泡、事件源对象进行处理,提高性能和灵活性;
优化版:利用事件冒泡,点击li, li冒泡向ul;ul执行函数会执行; 利用事件源对象,得到最终点击的是谁;输出事件源对象的InnerHTML即可;
7、事件分类:以下都是常用事件类型;
(1).鼠标事件:click;dblclick;contextmenu; mousemove; mousedown/mouseup; mouseover;/mouseout; mouseenter;/mouseleave;
[1].onclick = onmousedown + onmouseup;(完成按下+弹起才是完整的点击事件)
[2].DOM3标准规定:click事件只能监听左键,只能通过mousedown和mouseup来判断鼠标键;(event事件对象中的button属性值:0:左; 1:滚轮; 2:右)(chick事件右键为出菜单contextmenu;)
[3].鼠标拖拽事件:(拖着物块运动) 【解决bug使用的是在document文档上触发事件,还有一种解决方案,也可称其为捕获(不是很严格),div.setCapture();//仅在IE浏览器好使,dom元素会将页面中所有的事件硬捕获到自己身上,常与div.releaseCapture();配套使用//捕获后需要释放,因为其对其他事件有坏处】
[4].解决mousedown和click的冲突:(解决其是点击or拖拽)例:a标签制作的物块,如何判断点击跳转还是拖拽其移动?(根据生物行为特征时间差)
补充:[1].click,dblclick,多次点击计算总点击次数除以1/2来确认触发事件频次; [2].contextmenu:应用场景最多的是阻止右键出菜单事件; [3].mousemove往往与mousedown/up配套使用; [4].mouseenter/mouseleave:鼠标移入触发,其不会发生冒泡;mouseover/mouseout:鼠标移入触发,其会发生冒泡;(一般使用前者) [5].css中的hover底层是用js实现的,html中的form表单提交功能底层用js中submit事件实现,相比于js代码直接去操作,html/css是直接由底层引擎实现,速度更快,hover肯定比js实现的更快; [6].移动端使用的是click;/touchmove/touchstart;/touchend;
(2).键盘事件:keydown keypress keyup;
[1].触发顺序:keydown -->> keypress -->>keyup; 相比于鼠标事件,键盘事件onkeydown按下会连续触发,直到onkeyup;(根据应用场景设计,游戏设计中绑定keydown事件)
[2].keydown和keypress区别:只有按下便会触发两个事件类型,keydown>keypress;
区别:keydown可以检测所有键盘类按键,除了fn(辅助按键);keypress只能检测字符类按键(ASCII码表中的按键);两者触发事件的event对象有charCode();可返回ASCII码,keydown中event.charCode;//都为0;控制类按键(上/下/左/右,ctrl/shift/alt)没有keypress;因为没有ASCII码对应
keypress返回ASCII码,可转换为相应的字符,有一定的应用场景;String.fromCharCode();//String静态类的静态方法,参数传入ASCII码,返回相应字符;shift+a; alt+a;//也OK;
键盘类事件event事件对象中witch属性表示的是键盘108个键中的键号,其和ASCII码没关系;
(3).文本操作事件:input change focus blur;
[有bug,当输入"请输入用户名"时,焦点离开没问题,焦点再聚焦到输入框时,内容便会清空;大厂也有此bug]
(4).窗体操作类window上的事件:scroll load;
window.onscroll = function(){};
window.onload = function(){};//一般不要把主程序放到函数体,window.onload是指网页内容全部加载完成,不同于文档加载完成,网速不好的情况下1k未加载成功都会影响后续的操作;当然也有应用场景:广告显示(页面全部加载完成后,触发广告部分);
window.onload=function(){}; 整个页面加载完成后执行; $(document).ready(function(){ }); jquery中这种方式表示dom解析完就执行;document.addEventListener('DOMContentLoaded',function(){},false); dom解析完成后就执行;[此事件没有句柄的方式,只能使用addEventListener();]