1.DOM0 事件和DOM2级在事件监听使用方式上有什么区别?
DOM0事件有两种:
一是在标签内写事件
二是在js写node. = function() {};
第二种方法事件处理程序被认为是元素的方法,事件处理程序在元素的作用域下运行,所以同一执行上下文中只能存在一种事件处理程序。
DOM2级事件定义了两个方法用于处理指定和删除事件处理程序的操作:
addEventListener
removeEventListener
所有的DOM节点都包含这两个方法,并且它们都接受三个参数:
事件类型
事件处理方法
布尔参数,如果是true表示在捕获阶段调用事件处理程序,如果是false,则是在事件冒泡阶段处理
DOM2级事件规定事件流包括三个阶段,事件捕获阶段,处于目标阶段,事件冒泡阶段,首先发生的是事件捕获,为截取事件提供机会,然后是实际目标接收事件,最后是冒泡阶段
141533286861687.png
DOM2级事件的两个方法好处在于在元素作用域下同一执行上下文中可以存在多个事件处理程序
2.attachEvent与addEventListener的区别?
添加事件处理程序事addEventListener和attachEvent主要有几个区别:
参数个数不相同,这个最直观,addEventListener有三个参数,attachEvent只有两个,attachEvent添加的事件处理程序只能发生在冒泡阶段,addEventListener第三个参数(true/false)可以决定添加的事件处理程序是在捕获阶段还是冒泡阶段处理(我们一般为了浏览器兼容性都设置为冒泡阶段)
第一个参数意义不同,addEventListener第一个参数是事件类型(比如click,load),而attachEvent第一个参数指明的是事件处理函数名称(,)
事件处理程序的作用域不相同,addEventListener的作用域是元素本身,this是指的触发元素,而attachEvent事件处理程序会在全局变量内运行,this是window,所以刚才例子才会返回undefined,而不是元素id
为一个事件添加多个事件处理程序时,执行顺序不同,addEventListener添加会按照添加顺序执行,而attachEvent添加多个事件处理程序时顺序无规律(添加的方法少的时候大多是按添加顺序的反顺序执行的,但是添加的多了就无规律了),所以添加多个的时候,不依赖执行顺序的还好,若是依赖于函数执行顺序,最好自己处理,不要指望浏览器
3. 解释IE事件冒泡和DOM2事件传播机制?
IE事件冒泡的流程是,当监测到一个事件发生时,事件会从目标元素开始向父级传递,直到传递到window(document)停止。这期间,如果遇到同样的事件,都会激活对应的事件处理程序。
DOM2的时间传播机制包括了事件冒泡机制作为事件传播的第三阶段,并且加入了第一阶段:事件捕获,即与冒泡机制相反,侦听到事件时,事件先从document开始再到子元素一层层直到目标元素。第二阶段: 处于目标阶段,此时事件在div上发生,被看做冒泡的一部分。
在兼容所有浏览器的事件处理程序上主要采用冒泡机制作为事件传播机制。
同时也衍生出了解决当需要在父元素下进行新增的子元素的操作所造成无法触发事件或者事件方法复杂的技巧,如:
<body> <ul> <li>01</li> <li>02</li> <li>03</li> </ul> <script type="text/javascript"> function $(id) { return document.querySelector(id); } $('ul').addEventListener('click', function(e) { if(e.target.tagName.toLowerCase() === 'li') { console.log(e.target.innerHTML); } }); </script> </body>
4.如何阻止事件冒泡? 如何阻止默认事件?
阻止事件冒泡
<body> <ul> <li>01</li> <li>02</li> <li>03</li> </ul> <script type="text/javascript"> function $(id) { return document.querySelector(id); } function $$(id) { return document.querySelectorAll(id); } [].forEach.call($$('li'), function(node) { node.addEventListener('click', function(e) { e.stopPropagation(); //阻止事件冒泡方法 console.log(e.target.innerHTML); }); }) //当父元素也设置了点击事件时,点击子元素也会触发父元素事件处理程序 $('ul').addEventListener('click',function(e) { console.log(e.target); }) </script></body>
阻止默认事件
<body>
<a href="http://www.jirengu.com">饥人谷官网</a><script type="text/javascript"> function $(id) { return document.querySelector(id); } $('a').addEventListener('click', function(e) { e.preventDefault(); console.log('阻止跳转...') }) </script></body>
5.有如下代码,要求当点击每一个元素li时控制台展示该元素的文本内容。不考虑兼容
<ul> <li>这里是</li> <li>饥人谷</li> <li>前端6班</li> </ul> <script type="text/javascript"> $('ul').addEventListener('click',function(e){ if(e.target.tagName.toLowerCase() === 'li') { console.log(e.target.innerHTML); } }) function $(id) { return document.querySelector(id); } function $$(id) { return document.querySelectorAll(id); } </script>
6.补全代码,要求:
当点击按钮开头添加时在
<li>
这里是</li>
元素前添加一个新元素,内容为用户输入的非空字符串;当点击结尾添加时在最后一个 li 元素后添加用户输入的非空字符串.当点击每一个元素li时控制台展示该元素的文本内容。
<ul class="ct"> <li>这里是</li> <li>饥人谷</li> <li>任务班</li> </ul> <input class="ipt-add-content" placeholder="添加内容"/> <button id="btn-add-start">开头添加</button> <button id="btn-add-end">结尾添加</button> <script type="text/javascript"> var content = $('.ipt-add-content'); var btnStart = $('#btn-add-start'); var btnEnd = $('#btn-add-end'); $('ul').addEventListener('click',function(e){ if(e.target.tagName.toLowerCase() === 'li') { console.log(e.target.innerHTML); } }); btnStart.addEventListener('click',function(){ var addLi = document.createElement('li'); if(content.value) { addLi.innerHTML = content.value; $('ul').insertBefore(addLi,$('ul').children[0]); }else{ console.log('请填写内容后再添加!') } }); btnEnd.addEventListener('click',function(){ var addLi = document.createElement('li'); if(content.value) { addLi.innerHTML = content.value; $('ul').appendChild(addLi); }else{ console.log('请填写内容后再添加!') } }); function $(id) { return document.querySelector(id); } function $$(id) { return document.querySelectorAll(id); } </script>
7.补全代码,要求:当鼠标放置在li元素上,会在img-preview里展示当前li元素的data-img对应的图片。
<ul class="ct"> <li data-img="http://cdn.jirengu.com/book.jirengu.com/img/11.jpg">鼠标放置查看图片1</li> <li data-img="http://cdn.jirengu.com/book.jirengu.com/img/13.jpg">鼠标放置查看图片2</li> <li data-img="http://cdn.jirengu.com/book.jirengu.com/img/14.jpg">鼠标放置查看图片3</li> </ul> <div class="img-preview"></div> <script type="text/javascript"> var ulCt = $('.ct'); var preview = $('.img-preview'); ulCt.addEventListener('mouseover',function(e){ if(e.target.tagName.toLowerCase() === 'li') { // console.log(e.toElement.getAttribute('data-img')) var address = e.toElement.getAttribute('data-img') var imgPreview = document.createElement('img'); imgPreview.setAttribute('src',address); preview.appendChild(imgPreview); } }); ulCt.addEventListener('mouseout',function(e){ if(e.target.tagName.toLowerCase() === 'li') { preview.innerHTML = ''; } }); function $(id) { return document.querySelector(id); } function $$(id) { return document.querySelectorAll(id); } </script>
8.事件兼容处理程序(github)
function binEvent(node,type,handler) { node['e' + type + handler] = handler; node[type + handler] = function(){ node['e' + type + handler](window.event) } node.attachEvent('on' + type,node[type + handler]); }
编写兼容IE上巧妙的运用了闭包和引用类型的特性,使用闭包将变量保存在引用类型数据地址中,而引用类型则是只要找到指针就可以找到对应存放数据的地址,不会像非引用类型一样数据改变而改变。
作者:饥人谷_米弥轮
链接:https://www.jianshu.com/p/0d93c6a6ffb6