# 移除事件与 bind

# addEventListener() 添加监听事件

  • 语法

    obj.addEventListener(type, listener[, useCapture])

    obj.addEventListener(type, listener [,{capture: Boolean, once: Boolean, passive: Boolean}])

  • obj

    需要添加的事件的对象 必须是对象节点

  • type

    需要监听的事件类型

  • listener

    需要监听的 EventListener 函数 必须和 removeEventListener 绑定的事件内存保持一致 否则移除不了

  • useCapture

    布尔值 默认是 false 指事件句柄处于捕获阶段

  • capture

    布尔值 默认是 false 指事件句柄处于捕获阶段 如果设置为 true 不管 bubbling 设置什么都会变为冒泡阶段

  • once

    布尔值,默认是 false 事件会多次触发 如果想触发一次可以变为 true

  • passive (opens new window)

    布尔值,默认是 true 代表该监听器内部不会调用 preventDefault 函数来阻止默认滑动行为

  • 事件设置冒泡阶段

    var baba = document.querySelector(".baba"),
        son = document.querySelector(".son");
    baba.addEventListener("click",function(){
      console.log("baba")
    },true)
    son.addEventListener("click",function(){
      console.log("son")
    })
    
    1
    2
    3
    4
    5
    6
    7
    8
  • 绑定一次事件

    document.querySelector(".baba").addEventListener("click",function(){
      console.log("baba")
    },{
      once:true
    })
    
    1
    2
    3
    4
    5

# removeEventListener() 移除监听事件

  • 语法

    obj.removeEventListener(type, listener[, useCapture])

  • obj

    需要移除的事件的对象 必须是对象节点

  • type

    需要移除的事件类型

  • listener

    需要移除的 EventListener 函数 必须和 addEventListener 绑定的事件内存保持一致 否则移除不了

  • useCapture

    布尔值 默认是 false 指事件句柄处于捕获阶段

  • 事件不执行,直接移除

    var btn = document.querySelector("button");
        btn.addEventListener("click", say);
        btn.removeEventListener("click", say);
        function say() {
          console.log(btn.classList);
        }
    
    1
    2
    3
    4
    5
    6
  • 事件执行一次后直接移除

    var btn = document.querySelector("button");
        btn.addEventListener("click", say);
        function say() {
          console.log(btn.classList);
          btn.removeEventListener("click", say);
        }
    
    1
    2
    3
    4
    5
    6

# bind() 绑定事件

  • 语法

    fun.bind(thisArg[, arg1[, arg2[, ...]]])

  • fun

    fun 只能是函数名 不能写成 function say(){}.bind()

  • thisArg

    当绑定函数被调用时 该参数会作为原函数运行时的 this 指向(也就是 this 放生了改变 并且当遇到 new 操作符时会失效)

  • arg1, arg2, ...

    当绑定函数被调用时 这些参数将置于实参传递给之前被绑定的方法作为形参

    btn.addEventListener("click",function(color,bg_color){
        this.style.color = color;
        this.style.bgColor = bg_color;
    }.bind(div,"red","blue"))
    
    1
    2
    3
    4
  • 描述

    1. 在使用 bind() 方法时是创建一个新函数(称为绑定函数) 相当于是被调函数的拷贝

    2. 当新函数被调用时 this 值是 bind() 的第一个参数 该参数不能被重写

    3. 正是因为 bind() 方法使用时会拷贝新的函数 所以会让 removeEventListener() 失效 因为内存指向不一致

      var h1 = document.querySelector("h1"),
          btn = document.querySelector("button"),
          num = 0;
      btn.addEventListener("click", change_color.bind(h1));
      function change_color() {
          ++num % 2 ? this.style.color = "blue" : this.style.color = "red";
          console.log(num);
          btn.removeEventListener("click", change_color.bind(h1));
      }
      
      1
      2
      3
      4
      5
      6
      7
      8
      9
    4. 在上面的例子中要确保移除 click 事件就必须保证 change_color 指向同一个内存地址.

      var h1 = document.querySelector("h1"),
          btn = document.querySelector("button"),
          my_color_fun = change_color.bind(h1),
          num = 0;
      btn.addEventListener("click", my_color_fun);
      function change_color() {
          ++num % 2 ? this.style.color = "blue" : this.style.color = "red";
          console.log(num);
         btn.removeEventListener("click", my_color_fun);
      }
      
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
    5. 可以通过 onclickaddEventListener() 的区别来清除监听事件.

      var h1 = document.querySelector("h1"),
          btn = document.querySelector("button"),
          num = 0;
      btn.onclick = function() {
          ++num % 2 ? this.style.color = "blue" : this.style.color = "red";
          console.log(num);
          btn.onclick = null;
      }.bind(h1)
      
      1
      2
      3
      4
      5
      6
      7
      8

# passive属性

  • 什么是被动事件侦听器?

    1. 被动事件侦听器是一种新兴的网络标准 是 Chrome 51 附带的一项新功能 通过消除滚动以阻止触摸和滚轮事件监听器的需要 开发人员可以选择加入以提高滚动性能

    2. 当我们通过事件调用 preventDefault() 来完全阻止滚动在事件时会报[Intervention] Unable to preventDefault inside passive event listener due to target being treated as passive (opens new window)

  • 禁止用户通过滚轮缩放页面的解决方案

    • Passive Event Listeners 特性当前仅支持 touchwheel 相关
    document.addEventListener("wheel", function(e) {
    	if (e.ctrlKey) {
    		e.preventDefault();
    	}
    },{
    	passive:false
    })
    
    1
    2
    3
    4
    5
    6
    7

# 总结

  1. 如果同一个对象分别为冒泡和捕获都添加了监听事件 那么这两次事件需要分别移除.两者不会互相干扰

  2. bind() 方法会拷贝原函数一份 而不是直接用原函数进行操作

  3. addEventListener()removeEventListener() 的对象 触发事件 执行函数的内存地址必须一致 否则清除不到

  4. addEventListener() 可以给对象注册一个或多个同类型的监听事件而 onclick 则是或者覆盖前者

  5. addEventListener() 可以更加精确的控制事件触发的阶段(冒泡或者捕获) 而 onclick 只能是捕获阶段

  6. addEventListener() 对所有的DOM元素都有效果 而 onclick 只能对HTML元素有效

  7. addEventListener() 添加监听事件时 会让this发生改变

  8. addEventListener() 添加监听事件时可以通过 once 绑定一次事件

# 面试问题

  1. 案例一

    this.age = 9;
    var melon = {
      age: 81,
      get_age: function () {
        return this.age;
      }
    };
    melon.get_age();   //问题一
    var get_age1 = melon.get_age;
    get_age1();        //问题二
    var get_age2 = get_age1.bind(melon);
    get_age2();        //问题三
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
  2. 案例二

    function add(a, b) {
      return a + b;
    }
    var a = 3,
        b = 4,
        newFoo = add.bind(this, a, b); //问题一
    a = 6;
    b = 7;
    newFoo(); //问题二
    
    1
    2
    3
    4
    5
    6
    7
    8
    9