[TOC]

事件处理程序

事件处理程序又叫事件监听器,实际上就是事件绑定函数。事件发生时,会执行相应的代码
事件处理机制分为4类

  1. DOM0级处理程序
  2. IE事件处理程序
  3. DOM2级事件处理程序
  4. html事件处理程序

    html事件处理程序

    <div id="divA" onClick="this.innerHTML = 'BBB'">AAA</div>
    <!-- this的应用 -->
    <script>
     function divClick() {
             divA.innerHTML = 'CCC';
     }
    </script>
    <!-- id的应用 -->
    <button onClick="divClick()">id的直接应用</button>
    <!-- event对象的应用 -->
    <div onClick="this.innerHTML += event.type">event对象的应用</div>
    <!-- 属性的应用 -->
    <button onClick="this.innerHTML = value" value="属性的应用">value</button>
    <script>
    var value = '123';
    </script>
    <intpu type="text" onClick="alert(value)"/>
    <!--
    注意 
    <script>
    var value = '123';
    </script>
    <input type="text" onClick="alert(value)"/>
    此时输出""
    -->
    <form>
     <input type="text" name="username" value="123"/>
     <input type="button" value="按钮" onClick="alert(username.value)"/> 
    </form>
    <!-- 
     此时this作用域链是 this->this.form->document
     function中的this不等于document中的this
    -->
    

    DOM0级处理程序

    <div id="box"></div>
    <script>
     box.onclick = function(event){
         this.innerHTML += 1;
         // 此时this与dom中一致
     }
     box.onclick = null; // 清楚此事件
     // 每个事件目标对于每一种事件类型,只能添加一个事件处理程序。
    </script>
    

    DOM2级事件处理程序

    <div id="box"></div>
    <script>
     // IE8以上就支持这种语法了
     function a(){
         // ...        
     }
     // 参数列表:事件类型,事件触发函数,事件处理类型ture捕获,false冒泡,默认为冒泡
     box.addEventListener('click', a, true);
     box.removeEventListener('click', '事件触发函数名');
     // addEventListener此种方式支持添加多个相同事件,以添加顺序执行触发顺序
    </script>
    

    IE事件处理程序

    ```html

    
    <a name="z1J20"></a>
    ## 四种事件的顺序
    DOM0级会覆盖HTML事件处理程序<br />chrome,opera,safari等webkit内核会按定义顺序执行<br />firefox和ie优先执行DOM0级
    
    <a name="lkO6t"></a>
    ### 浏览器默认行为与冒泡
    event.preventDefault ? event.preventDefault() : (event.returnValue = false); 
    <a name="Ta8rN"></a>
    ### 阻止默认行为 return false; 也能阻止默认行为,并且在jquery中还能阻止冒泡
    event.stopPropagetion ? event.stopPropagation() : (window.event.cancelBubble = true);
    
    <a name="44VoE"></a>
    ### event.repeat 
    是返回键盘长按事件的,首次触发会返回false,在部分浏览器中,例如window中,有可能长按会无数次触发事件,加入下面代码可以解决此问题<br />if (event.repeat) {<br />return<br />}
    
    <a name="ET7G3"></a>
    ### 自定义事件
    ```javascript
    var eventTarget = function() {
        this.__listener = {};
    }
    eventTarget.prototype = {
        addEvents:function(){},
        fireEvents:function(){},
        removeEvents:function(){},
    }
    var myEvents = new eventTarget();
    myEvents.addEvents(
      {
          "once": function () { // click
            alert('只出现一次')
            this.removeEvents('once')
            },
        "infinity": function() { // click
            alert('每次都执行');
        }
    });
    
    
    document.onclick = function(){ // 监听 
        e = e || window.event;
        var target = e.target || e.srcElemet;
        if (!target || !/input|pre/i.test(target.tarName)) {
            myEvent.fireEvents(["onec","infinity"]);
        }
    }
    
    divA.addEventListener('alert', function(){
        alert('alert');
    }, false);
    console.log(divA);
    divA.addEventListener('click', function(){
        alert('666');
        var evt = document.createEvent('MouseEvent');
        evt.initMouseEvent('alert', false, false);
    
        // var evt = document.createEvent('HTMLEvents');
        // evt.initEvent('alert', false, false); // 两种都可以
    
        divA.dispatchEvent(evt);
    }, true);
    
    // event-emitter
    

    观察者模型

    /**
    *  @description 观察者列表(目标)
    */
    class ObserverList {
      constructor() {
        this.observerList = []
      }
      add(observer) {
        return this.observerList.push(observer);
      }
      remove(observer) {
        this.observerList = this.observerList.filter(ob => ob !== observer);
      }
      count() {
        return this.observerList.length;
      }
      get(index) {
        return this.observerList[index];
      }
    }
    
    /**
    *  @description 事件调度对象
    */
    class PubSub {
      constructor() {
          this.subscribers = {}
      }
      subscribe(type, fn) {
          if (!Object.prototype.hasOwnProperty.call(this.subscribers, type)) {
            this.subscribers[type] = [];
          }
          this.subscribers[type].push(fn);
      }
      unsubscribe(type, fn) {
          let listeners = this.subscribers[type];
          if (!listeners || !listeners.length) return;
          this.subscribers[type] = listeners.filter(v => v !== fn);
      }
      publish(type, ...args) {
          let listeners = this.subscribers[type];
          if (!listeners || !listeners.length) return;
          listeners.forEach(fn => fn(...args));        
      }
    }
    
    
    class SubjectClass {
        // 观察者列表
      this.observers = new ObserverList();
    
      // 观察者模式的方法
      this.addObserver = function (observer) {
        this.observers.add(observer);
      }
    
      // 观察者模式的方法
      this.removeObserver = function (observer) {
        this.observers.remove(observer);
      }
    
      // 通知观察者更新
      this.notify = function (options) {
        let obCount = this.observers.count();
        for (let index = 0; index < obCount; index++) {
          if (this.observers.get(index).update) {
            this.observers.get(index).update(options);
          }
        }
      }
    
        // 事件调度对象
      this.pubSub = new PubSub();
    }