[JavaScript] JavaScript事件注册,事件委托,冒泡,捕获,事件流
面试题 event 事件
- 事件委托是什么?
- 如何阻止事件冒泡,阻止默认事件呢?
- Javascript 的事件流模型都有什么?
- 事件绑定和普通事件有什么区别?

Event 对象
Event 对象,当事件发生的时候出发某个函数,该 Event 对象将自动在函数内可用,该对象包含了很多事件触发时候的信息,
但 IE 却没有这么实现,而是自己实现的,IE 浏览器是通过全局对象 window 下的 event 属性来包含这些信息
function myEventHandler(e) {
    // 注意参数e
    // 该函数调用的时候e是event对象(W3C实现)
    // 兼容IE的代码
    e = e || window.event;
    // 现在e就可以兼容各种浏览器了
}
事件注册
这里最重要的就是 IE 的 attachEvent 和 W3C 标准 addEventListener 在执行上的一些区别
- attachEvent 只支持事件冒泡 addEventListener 既支持事件冒泡,也支持事件捕获
- 参数:attachEvent 事件类型需要 on 前缀 addEventListener 事件类型不需要 on 前缀
- 如果使用 attachEvent 对一个元素的目标阶段绑定了多次事件,那么会按照绑定顺序的相反顺序进行触发。如果使用 addEventListener 对一个元素的目标阶段绑定了多次事件,那么会按照绑定顺序进行触发
w3c
var oBtn = document.getElementById("btn1");
oBtn.addEventListener('click', introClick, false);
ie
var oBtn = document.getElementById("btn1");
oBtn.attachEvent('onclick', introClick);
兼容写法
      var oBtn = document.getElementById("btn1");
      addEvent(oBtn, "click", show);
      addEvent(oBtn, "click", show2);
      // removeEvent(oBtn, "click", show);
      //对象.addEventListener(事件名,函数,false);	for 高
      //事件名	onclick	over/out/down/up.........不带on
      //函数	obj.onclick=show	show==函数
      function addEvent(obj, eve, fn) {
        if (obj.addEventListener) {
          obj.addEventListener(eve, fn, false); //由于事件参数不带on
        } else {
          obj.attachEvent("on" + eve, fn); //所以这里的绑定事件要将on补上
        }
      }
      //解绑
      //对象.removeEventListener(事件名,函数,false);  chrome FF IE 9 10
      //对象.detachEvent(事件名,函数);        IE 6 7 8
      // oBtn.detachEvent('onclick',show2);
      //移除函数
      function removeEvent(obj, eve, fn) {
        if (obj.removeEventListener) {
          obj.removeEventListener(eve, fn, false);
        } else {
          obj.detachEvent("on" + eve, fn);
        }
      }
      function show() {
        alert("我将弹出1");
      }
      function show2() {
        alert("我将弹出2");
      }
删除匿名函数的引用
addEvent(oBtn, 'click', function(){
    alert("弹出1");
    //arguments对象包含了所有传递进来的参数以及该函数自身(callee)
    console.log(arguments);
    removeEvent(oBtn, 'click', arguments.callee);
});

W3C 和微软模型还有其他的少许差异,callee 是返回正在被执行的 function 函数,也就是所指定的 function 对象的正文。arguments.callee 知道就好了,别在代码中用了
事件冒泡和捕获
当年,IE 是冒泡流,而网景是捕获流,W3C 费些力使 JS 支持了冒泡流和捕获流。但是前些年或者更之前的时候,IE 还是老大,于是早期的 IE 浏览器并不支持捕获。
冒泡
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <title>事件冒泡</title>
    <style></style>
    <script>
      window.onload = function() {
        _id("div1").addEventListener(
          "click",
          function() {
            alert(_id("div1").style.background);
          },
          false
        );
        _id("div2").addEventListener(
          "click",
          function() {
            alert(_id("div2").style.background);
          },
          false
        );
        _id("div3").addEventListener(
          "click",
          function() {
            alert(_id("div3").style.background);
          },
          false
        );
        function _id(id) {
          return document.getElementById(id);
        }
      };
    </script>
  </head>
  <body>
    <div id="div1" style="width:500px; height:500px; background:red;">
      <div id="div2" style="height:300px; width:300px; background:yellow">
        <div id="div3" style="width:100px; height:100px; background:blue"></div>
      </div>
    </div>
  </body>
</html>
捕获
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <title>事件捕获</title>
    <style></style>
    <script>
      window.onload = function() {
        var oDiv1 = document.getElementById("div1");
        var oDiv2 = document.getElementById("div2");
        var oDiv3 = document.getElementById("div3");
        oDiv1.addEventListener(
          "click",
          function() {
            alert(oDiv1.style.background);
          },
          true
        );
        oDiv2.addEventListener(
          "click",
          function() {
            alert(oDiv2.style.background);
          },
          true
        );
        oDiv3.addEventListener(
          "click",
          function() {
            alert(oDiv3.style.background);
          },
          true
        );
      };
    </script>
  </head>
  <body>
    <div id="div1" style="width:500px; height:500px; background:red;">
      <div id="div2" style="height:300px; width:300px; background:yellow">
        <div id="div3" style="width:100px; height:100px; background:blue"></div>
      </div>
    </div>
  </body>
</html>
addEventListener 的第三个参数 true 就是捕获,false 就是冒泡
阻止默认行为
    <script type="text/javascript">
      var oBtn = document.getElementById("btn1");
      addEvent(oBtn, "click", myEventHandler);
      //对象.addEventListener(事件名,函数,false);	for 高
      //事件名	onclick	over/out/down/up.........不带on
      //函数	obj.onclick=show	show==函数
      function addEvent(obj, eve, fn) {
        if (obj.addEventListener) {
          obj.addEventListener(eve, fn, false); //由于事件参数不带on
        } else {
          obj.attachEvent("on" + eve, fn); //所以这里的绑定事件要将on补上
        }
      }
      function myEventHandler(e) {
        e = e || window.event;
        // 防止默认行为
        if (e.preventDefault) {
          e.preventDefault();
        } else {
          e.returnValue = false;
        }
      }
    </script>
禁止一下鼠标右键
    document.getElementById("contextmenu").addEventListener(
      "contextmenu",
      function(ev) {
        var oEvt = ev || event;
        oEvt.preventDefault(); //阻止默认
      },
      false
    );
阻止冒泡
<script>
      window.onload = function() {
        _id("div1").addEventListener(
          "click",
          function() {
            alert(_id("div1").style.background);
          },
          false
        );
        _id("div2").addEventListener(
          "click",
          function() {
            alert(_id("div2").style.background);
          },
          false
        );
        _id("div3").addEventListener("click", myParagraphEventHandler, false);
        function _id(id) {
          return document.getElementById(id);
        }
        function myParagraphEventHandler(e) {
          alert(this.style.background);
          e = e || window.event;
          // 停止向上冒泡
          if (e.stopPropagation) {
            // W3C实现
            e.stopPropagation();
          } else {
            // IE实现
            e.cancelBubble = true;
          }
        }
      };
    </script>
为什么我们要阻止默认事件呢?
- 异步操作
- 提交表单之前对表单进行一些基本的验证,比如邮箱是否合法,用户名是不是满足指定的格式,为了不让 a 点击之后跳转,我们就要给他的点击事件进行阻止
- 文本框获得焦点
事件委托
事件委托描述的是将事件绑定在容器元素上,然后通过判断点击的 target 子元素的类型来触发相应的事件
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>Title</title>
  </head>
  <body>
    <table id="my-table">
      <tr>
        <td>1</td>
        <td>2</td>
        <td>3</td>
      </tr>
      <tr>
        <td>4</td>
        <td>5</td>
        <td>6</td>
      </tr>
      <tr>
        <td>7</td>
        <td>8</td>
        <td>9</td>
      </tr>
      <tr>
        <td>11</td>
        <td>22</td>
        <td>33</td>
      </tr>
      <tr>
        <td>44</td>
        <td>55</td>
        <td>66</td>
      </tr>
    </table>
  </body>
  <script>
    var myTable = document.getElementById("my-table");
    myTable.onclick = function(e) {
      // 处理浏览器兼容
      e = e || window.event;
      var targetNode = e.target || e.srcElement;
      if (targetNode.nodeName.toLowerCase() === "td") {
        alert("You clicked a table row!");
      }
    };
  </script>
</html>
DOM 事件流
这就是为什么捕获事件中,目标阶段是最后。而在冒泡事件中,目标阶段是最先了

面试题答案
- 
利用事件冒泡的原理,让自己的所触发的事件,让他的父元素代替执行 2.阻止冒泡 ie 是 ;其他是; 
- 
浏览器 阻止冒泡 阻止默认 ie ev.cancelBubble = true return false 其他 ev.stopPropagation() ev.preventDefault() 
- 
"事件冒泡":事件开始由最具体的元素接受,然后逐级向上传播 
 "事件捕捉":事件由最不具体的节点先接收,然后逐级向下,一直到最具体的
 "DOM 事件流":三个阶段:事件捕捉,目标阶段,事件冒泡
- 
xxx.onEvent = function(){}其实是赋值操作,下面取缔上面的。而事件绑定可以一口气绑定多个事件,按绑定顺序执行 
xxx.onEvent 就是对监听属性赋值一个函数,取消绑定设置为空就好了 xxx.onEvent = null
常见事件
鼠标事件
- mousedown 鼠标设备按下一个元素的时候触发 mousedown 事件
- mouseup 鼠标设备从按下的元素上弹起的时候触发 mouseup 事件
- click 鼠标点击元素的时候触发 click 事件
- dblclick 鼠标双击元素的时候触发 dblclick 事件
- mouseover 鼠标移动到某元素上的时候触发 mouseover 事件
- mouseout 鼠标从某元素离开的时候触发 mouseout 事件
- mousemove 鼠标在某元素上移动但未离开的时候触发 mousemove 事件
键盘事件
- keypress 按键按下的时候触发该事件
- keydown 按键按下的时候触发该事件,并且在 keypress 事件之前
- keyup 按键松开的时候触发该事件,在 keydown 和 keypress 事件之后
表单事件
- select 文本字段(input, textarea 等)的文本被选择的时候触发该事件
- change 控件失去 input 焦点的时候触发该事件(或者值被改变的时候)
- submit 表单提交的时候触发该事件
- reset 表单重置的时候触发该事件
- focus 元素获得焦点的时候触发该事件,通常来自鼠标设备或 Tab 导航
- blur 元素失去焦点的时候触发该事件,通常来自鼠标设备或 Tab 导航
其它事件
- load 页面加载完毕(包括内容、图片、frame、object)的时候触发该事件
- resize 页面大小改变的时候触发该事件(例如浏览器缩放)
- scroll 页面滚动的时候触发该事件
- unload 从页面或 frame 删除所有内容的时候触发该事件(例如离开一个页面)

 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号