JavaScript中事件的绑定与解绑

1,978 阅读3分钟

一、事件的绑定

在Javascript中,事件绑定一共有3种方式:
① 行内绑定

  • <标签 属性列表 事件=”事件的处理程序” />
  • <input type=’button’ onclick=’display()’ />
  • this指向window ② 动态绑定
  • dom对象.事件 = 事件的处理程序(通常是一个匿名函数)
  • this指向了当前正在操作的dom对象

③ 事件监听

  • addEventListener
    • 三个参数
    • 谷歌,火狐,IE11支持,IE8不支持
    • addEventListener 中的this指向当前绑定事件的对象
    • 事件的类型无on
  • attachEvent
    • 两个参数
    • 谷歌火狐不支持,IE11不支持,IE8支持
    • attachEvent中的this指向window
    • 事件的类型有on

1. 对象.on事件名字=事件处理函数

缺点: 如果绑定多个事件,前面的事件会被后面的事件覆盖

<input type="button" value="按钮" id="btn" />

<script>
  document.getElementById("btn").onclick = function () {
    console.log("第一");
  };
  document.getElementById("btn").onclick = function () {
    console.log("第二");
  };
</script>

2. 对象.addEventListener("没有on的事件名字",事件处理函数,false);

解释:第三个参数在本篇文章的事件阶段中有解释 优点:可以绑定多个事件 缺点:谷歌、火狐、IE11支持,IE8不支持

<input type="button" value="按钮" id="btn" />

<script>
  document.getElementById("btn").addEventListener("click", function () {
    console.log("第一");
  }, false);
  document.getElementById("btn").addEventListener("click", function () {
    console.log("第二");
  }, false);
</script>

3. 对象.attachEvent("有on的事件名字",事件处理函数);

优点:可以绑定多个事件 缺点:谷歌、火狐、IE11不支持,IE8支持

<input type="button" value="按钮" id="btn" />

<div id="dv"></div>
<script>
  document.getElementById("btn").attachEvent("onclik", function () {
    console.log("第一");
  });
  document.getElementById("btn").attachEvent("click", function () {
    console.log("第二");
  }, false);
</script>

4. 兼容代码

<input type="button" value="第一个按钮" id="btn" />

<script>
  //为任意元素.绑定任意的事件, 任意的元素,事件的类型,事件处理函数
  function addEventListener(element, type, fn) {
    //判断浏览器是否支持这个方法
    if (element.addEventListener) {
      element.addEventListener(type, fn, false);
    } else if (element.attachEvent) {
      element.attachEvent("on" + type, fn);
    } else {
      element["on" + type] = fn;
    }
  }

  addEventListener(document.getElementById("btn"), "click", function () {
    console.log("码仙1");
  });
  addEventListener(document.getElementById("btn"), "click", function () {
    console.log("码仙2");
  });
  addEventListener(document.getElementById("btn"), "click", function () {
    console.log("码仙3");
  });
</script>

二、事件的解绑

用什么方式绑定事件,就应该用对应的方式解绑事件

  • 对象.on事件名字=事件处理函数

  • 对象.on事件名字=null; --> 解绑事件  

  • 对象.addEventListener("没有on的事件类型",命名函数,false);

  • 对象.removeEventListener("没有on的事件类型",函数名字,false); --> 解绑事件  

  • 对象.attachEvent("on事件类型",命名函数);

  • 对象.detachEvent("on事件类型",函数名字); --> 解绑事件

1. 对象.on事件名字=null;

<input type="button" value="第一个按钮" id="btn1" />
<input type="button" value="干掉第一个按钮的事件" id="btn2" />

<script>
  document.getElementById("btn1").onclick = function () {
    console.log("码仙");
  };
  document.getElementById("btn2").onclick = function () {
    document.getElementById("btn1").onclick = null;
  };
</script>

2. 对象.removeEventListener("没有on的事件类型",函数名字,false);

<input type="button" value="第一个按钮" id="btn1" />
<input type="button" value="干掉第一个按钮的事件" id="btn2" />

<script>
  function f1() { console.log("第一个"); };
  function f2() { console.log("第二个"); };
  document.getElementById("btn1").addEventListener("click", f1, false);
  document.getElementById("btn1").addEventListener("click", f2, false);

  //点击第二个按钮把第一个按钮的第一个点击事件解绑
  document.getElementById("btn2").onclick = function () {
    //解绑事件的时候,需要在绑定事件的时候,使用命名函数
    document.getElementById("btn1").removeEventListener("click", f1, false);
    document.getElementById("btn1").removeEventListener("click", f2, false);
  };
</script>

3. 对象.detachEvent("on事件类型",函数名字);

<input type="button" value="第一个按钮" id="btn1" />
<input type="button" value="干掉第一个按钮的事件" id="btn2" />

<script>
  function f1() { console.log("第一个"); };
  function f2() { console.log("第二个"); };

  document.getElementById("btn1").attachEvent("onclick", f1);
  document.getElementById("btn1").attachEvent("onclick", f2);

  document.getElementById("btn2").onclick = function () {
    document.getElementById("btn1").detachEvent("onclick", f1);
  };
</script>

4. 兼容代码

<input type="button" value="按钮" id="btn1" />
<input type="button" value="干掉第一个按钮的事件" id="btn2" />

<script>
  //绑定事件的兼容
  function addEventListener(element, type, fn) {
    if (element.addEventListener) {
      element.addEventListener(type, fn, false);
    } else if (element.attachEvent) {
      element.attachEvent("on" + type, fn);
    } else {
      element["on" + type] = fn;
    }
  }

  //为任意的一个元素,解绑对应的事件
  function removeEventListener(element, type, fnName) {
    if (element.removeEventListener) {
      element.removeEventListener(type, fnName, false);
    } else if (element.detachEvent) {
      element.detachEvent("on" + type, fnName);
    } else {
      element["on" + type] = null;
    }
  }

  function f1() { console.log("第一个"); }
  function f2() { console.log("第二个"); }

  addEventListener(document.getElementById("btn1"), "click", f1);
  addEventListener(document.getElementById("btn1"), "click", f2);

  document.getElementById("btn2").onclick = function () {
    removeEventListener(document.getElementById("btn1"), "click", f1);
    removeEventListener(document.getElementById("btn1"), "click", f2);
  };
</script>

三、事件阶段

通过 e.eventPhase 这个属性可以知道当前事件在哪个阶段
如果这个属性的值是:
1 ---->捕获阶段
2 ---->目标阶段
3 ---->冒泡阶段
一般默认都是冒泡阶段,很少用捕获阶段
冒泡阶段:从里向外
捕获阶段:从外向里
addEventListener方法的第三个参数是false的时候是冒泡阶段
addEventListener方法的第三个参数是true的时候是捕获阶段

<style>
  #div1 {
    width: 300px;
    height: 200px;
    background-color: red;
  }

  #div2 {
    width: 250px;
    height: 150px;
    background-color: green;
  }

  #div3 {
    width: 200px;
    height: 100px;
    background-color: blue;
  }
</style>

<div id="div1">
  <div id="div2">
    <div id="div3"></div>
  </div>
</div>

<script>
  //同时注册点击事件
  var objs = [document.getElementById("div3"), document.getElementById("div2"), document.getElementById("div1")];

  objs.forEach(function (ele) {    //遍历注册事件
    ele.addEventListener("click", function (e) {  //为每个元素绑定事件
      console.log(this.id + " ====> " + e.eventPhase);
    }, true);
  });
</script>

image.png 点击蓝色后 image.png addEventListener方法的第三个参数是 false 的时候,点击蓝色div,这时候为冒泡阶段 image.png

四、事件冒泡

多个元素嵌套,有层次关系,这些元素都注册了相同的事件,如果里面的元素的事件触发了,外面的元素的该事件自动的触发了

<style>
  #div1 {
    width: 300px;
    height: 200px;
    background-color: red;
  }

  #div2 {
    width: 250px;
    height: 150px;
    background-color: green;
  }

  #div3 {
    width: 200px;
    height: 100px;
    background-color: blue;
  }
</style>

<div id="div1">
  <div id="div2">
    <div id="div3"></div>
  </div>
</div>

<script>
  document.getElementById("div1").onclick = function () {
    console.log(this.id);
  };
  document.getElementById("div2").onclick = function () {
    console.log(this.id);
  };
  document.getElementById("div3").onclick = function () {
    console.log(this.id);
  };
</script>

image.png 点击蓝色div后输出 image.png

1. 阻止事件冒泡 window.event.cancelBubble=true

<script>
    document.getElementById("dv1").onclick = function () {
        console.log(this.id);
    };
    document.getElementById("dv2").onclick = function () {
        console.log(this.id);
        //阻止事件冒泡,IE特有的,谷歌支持,火狐不支持
        window.event.cancelBubble=true;
        //阻止超链接默认跳转
        e.preventDefault() 
    };
    document.getElementById("dv3").onclick = function () {
        console.log(this.id);
    };
</script>

2. 阻止事件冒泡 e.stopPropagation()

<script>
    document.getElementById("dv1").onclick = function () {
        console.log(this.id);
    };
    document.getElementById("dv2").onclick = function (e) {
        console.log(this.id);
        //阻止事件冒泡,谷歌和火狐支持
        e.stopPropagation();
        //阻止超链接默认跳转
         e.preventDefault() 
    };
    document.getElementById("dv3").onclick = function () {
        console.log(this.id);
    };
</script>

五、为同一个元素绑定多个不同的事件,指向相同的事件处理函数

<input type="button" value="码仙" id="btn" />

<script>
  //为同一个元素绑定多个不同的事件,指向相同的事件处理函数
  document.getElementById("btn").onclick = f1;
  document.getElementById("btn").onmouseover = f1;
  document.getElementById("btn").onmouseout = f1;

  function f1(e) {
    switch (e.type) {
      case "click":
        alert("好帅哦");
        break;
      case "mouseover":
        this.style.backgroundColor = "red";
        break;
      case "mouseout":
        this.style.backgroundColor = "yellow";
        break;
    }
  }
</script>
<input type="button" value="码仙1" id="btn1" />
<input type="button" value="码仙2" id="btn2" />

<script>
  //同时注册点击事件
  var nodes = [document.getElementById("btn1"), document.getElementById("btn2")]

  nodes.forEach(item => {
    item.addEventListener("click", function (e) {
      console.log(this.id + "====>" + e.eventPhase)
    }, true)
  })
</script>

六、JS动态添加、删除classl类

<style>
  #div { width: 100px; height: 100px; }
  .primary { background-color: blue; }
  .warning { background-color: yellow; }
  .border{border-radius:20px; }
</style>

<div id="div" class="primary"></div>
<input type="button" value="删除" id="btn-del" class="but-primary" />
<input type="button" value="添加" id="btn-add" class="but-primary" />
<input type="button" value="替换" id="btn-replace" class="but-primary" />

<script>
  var divNode = document.getElementById("div")
  var divClassString = divNode.getAttribute("class")  //primary

  //删除
  document.getElementById("btn-del").addEventListener("click", function () {
    // divNode.removeAttribute("class")  //移除class属性
    var string = divClassString.replace("primary","") 
    divNode.setAttribute("class",string)
  })

  //添加
  document.getElementById("btn-add").addEventListener("click", function () {
    // var string = divClassString+ " border"
    var string = divClassString.concat(" border")
    divNode.setAttribute("class",string)
  })

  //替换
  document.getElementById("btn-replace").addEventListener("click", function () {
    var string = divNode.getAttribute("class").replace("primary", "warning") 
    divNode.setAttribute("class",string)
  })
</script>

七、JQuery中绑定事件的几种方法

主要有on() bind() live() delegate()等几种,相对应的
解绑是off() unbind() die() undelegate()

  • on()、bind()、live()、delegate()中除了bind(),其他的都可以给后来追加的元素对象添加绑定事件。
  • 这几种方法中各自有对应支持的JQuery版本。
  • 在给动态添加的页面元素绑定事件时,通常用on()方法