• js事件代理(委托)


    JavaScript事件代理(委托)一般用于以下情况:

      1. 事件注册在祖先级元素上,代理其子级元素。可以减少事件注册数量,节约内存开销,提高性能。

      2. 对js动态添加的子元素可自动绑定事件。

    之前一直用各种js库的事件代理,如 jQuery,非常方便实用。今天尝试用原生 js 实现该功能。

      1 var addEvent = (function () {
      2   if (document.addEventListener) {
      3     return function (element, type, handler) {
      4       element.addEventListener(type, handler, false);
      5     };
      6   } else if (document.attachEvent) {
      7     return function (element, type, handler) {
      8       element.attachEvent('on' + type, function () {
      9         handler.apply(element, arguments);
     10       });
     11     };
     12   } else {
     13     return function (element, type, handler) {
     14       element['on' + type] = function () {
     15         return handler.apply(element, arguments);
     16       };
     17     };
     18   }
     19 })(),
     20 
     21 getClassElements = function (parentElement, classname) {
     22   var all, element, classArr = [], classElements = [];
     23 
     24   if (parentElement.getElementsByClassName) {
     25     return parentElement.getElementsByClassName(classname);
     26   } else {
     27     all = parentElement.getElementsByTagName('*');
     28 
     29     for (var i = 0, len = all.length; i < len; i++) {
     30       element = all[i];
     31       classArr = element && element.className && element.className.split(' ');
     32 
     33       if (classArr) {
     34         for (var j = 0; j < classArr.length; j++) {
     35           if (classArr[j] === classname) {
     36             classElements.push(element);
     37           }
     38         }
     39       }
     40     }
     41 
     42     return classElements;
     43   }
     44 },
     45 
     46 delegate = function () { // 参数:element, type, [selector,] handler
     47   var args = arguments,
     48   element = args[0],
     49   type = args[1],
     50   handler;
     51 
     52   if (args.length === 3) {
     53     handler = args[2];
     54     return addEvent(element, type, handler);
     55   }
     56 
     57   if (args.length === 4) {
     58     selector = args[2];
     59     handler = args[3];
     60 
     61     return addEvent(element, type, function (event) {
     62       var event = event || window.event,
     63       target = event.target || event.srcElement,
     64       quickExpr = /^(?:[a-zA-Z]*#([\w-]+)|(\w+)|[a-zA-Z]*\.([\w-]+))$/,
     65       match,
     66       idElement,
     67       elements,
     68       tagName,
     69       count = 0,
     70       len;
     71 
     72       if (typeof selector === 'string') {
     73         match = quickExpr.exec(selector);
     74 
     75         if (match) {
     76           // #ID selector
     77           if (match[1]) {
     78             idElement = document.getElementById(match[1]);
     79             tagName = match[0].slice(0, match[0].indexOf('#'));
     80 
     81           // tag selector
     82           } else if (match[2]) {
     83             elements = element.getElementsByTagName(selector);
     84 
     85           // .class selector
     86           } else if (match[3]) {
     87             elements = getClassElements(element, match[3]);
     88             tagName = match[0].slice(0, match[0].indexOf('.'));
     89           }
     90         }
     91 
     92         if (idElement) {
     93           if ( tagName ? tagName === idElement.nodeName.toLowerCase() && target === idElement : target === idElement ) {
     94             return handler.apply(idElement, arguments);
     95           }
     96         } else if (elements) {
     97           for (len = elements.length; count < len; count++) {
     98             if ( tagName ? tagName === elements[count].nodeName.toLowerCase() && target === elements[count] : target === elements[count] ) {
     99               return handler.apply(elements[count], arguments);
    100             }
    101           }
    102         }
    103       }
    104     });
    105   }
    106 };

    主要是用 apply 改变 this 的指向

    handler.apply(idElement, arguments);

    handler.apply(elements[count], arguments);

    测试一下:

    <style>
    #outer {padding: 50px; background-color: lightpink;}
    #inner {padding: 30px; background-color: aliceblue;}
    #paragraph1, #paragraph3 {background-color: cadetblue}
    </style>
    <div id="outer">outer
      <div id="inner">inner
        <p id="paragraph1" class="parag1">paragraph1</p>
        <p id="paragraph2" class="parag">paragraph2</p>
        <span>span</span>
        <p id="paragraph3" class="parag">paragraph3</p>
      </div>
    </div>
    var outer = document.getElementById('outer');
    
    delegate(outer, 'click', function () {
      console.log(this.id); // outer
    });
    delegate(outer, 'click', 'p', function () {
      console.log(this.id);  //点击 paragraph1 元素,输出其id为 "paragraph1"
    });

    模仿 jQuery 的风格,优化代码:

      1 (function () {
      2   var $ = function (element) {
      3     return new _$(element);
      4   };
      5 
      6   var _$ = function (element) {
      7     this.element = element && element.nodeType === 1 ? element : document;
      8   };
      9 
     10   _$.prototype = {
     11     constructor: _$,
     12 
     13     addEvent: function (type, handler, useCapture) {
     14       var element = this.element;
     15 
     16       if (document.addEventListener) {
     17         element.addEventListener(type, handler, (useCapture ? useCapture : false));
     18       } else if (document.attachEvent) {
     19         element.attachEvent('on' + type, function () {
     20           handler.apply(element, arguments);
     21         });
     22       } else {
     23         element['on' + type] = function () {
     24           return handler.apply(element, arguments);
     25         };
     26       }
     27 
     28       return this;
     29     },
     30 
     31     getClassElements: function (classname) {
     32       var element = this.element, all, ele, classArr = [], classElements = [];
     33 
     34       if (element.getElementsByClassName) {
     35         return element.getElementsByClassName(classname);
     36       } else {
     37         all = element.getElementsByTagName('*');
     38 
     39         for (var i = 0, len = all.length; i < len; i++) {
     40           ele = all[i];
     41           classArr = ele && ele.className && ele.className.split(' ');
     42 
     43           if (classArr) {
     44             for (var j = 0; j < classArr.length; j++) {
     45               if (classArr[j] === classname) {
     46                 classElements.push(ele);
     47               }
     48             }
     49           }
     50         }
     51 
     52         return classElements;
     53       }
     54     },
     55 
     56     delegate: function () { //参数:type, [selector,] handler
     57       var self = this,
     58       element = this.element,
     59       type = arguments[0],
     60       handler;
     61 
     62       if (arguments.length === 2) {
     63         handler = arguments[1];
     64         return self.addEvent(type, handler);
     65       } else if (arguments.length === 3) {
     66         selector = arguments[1];
     67         handler = arguments[2];
     68 
     69         return self.addEvent(type, function (event) {
     70           var event = event || window.event,
     71           target = event.target || event.srcElement,
     72           quickExpr = /^(?:[a-zA-Z]*#([\w-]+)|(\w+)|[a-zA-Z]*\.([\w-]+))$/,
     73           match,
     74           idElement,
     75           elements,
     76           tagName,
     77           count = 0,
     78           len;
     79 
     80           if (typeof selector === 'string') {
     81             match = quickExpr.exec(selector);
     82 
     83             if (match) {
     84               // #ID selector
     85               if (match[1]) {
     86                 idElement = document.getElementById(match[1]);
     87                 tagName = match[0].slice(0, match[0].indexOf('#'));
     88 
     89               // tag selector
     90               } else if (match[2]) {
     91                 elements = element.getElementsByTagName(selector);
     92 
     93               // .class selector
     94               } else if (match[3]) {
     95                 elements = self.getClassElements(match[3]);
     96                 tagName = match[0].slice(0, match[0].indexOf('.'));
     97               }
     98             }
     99 
    100             if (idElement) {
    101               if ( tagName ? tagName === idElement.nodeName.toLowerCase() && target === idElement ? target === idElement ) {
    102                 return handler.apply(idElement, arguments);
    103               }
    104             } else if (elements) {
    105               for (len = elements.length; count < len; count++) {
    106                 if ( tagName ? tagName === elements[count].nodeName.toLowerCase() && target === elements[count] : target === elements[count] ) {
    107                   return handler.apply(elements[count], arguments);
    108                 }
    109               }
    110             }
    111           }
    112         });
    113       }
    114     }
    115   };
    116 
    117   window.$ = $;
    118   return $;
    119 }());
    View Code

    使用如下:

    var outer = document.getElementById('outer');
    $(outer).delegate('click', '.parag', function (event) {
      console.log(this.id);
    });
  • 相关阅读:
    char/unsigned char/int/short 存储范围
    js 数字数组按大小排序
    【转】Vue生命周期
    mvn+spring+webapp模板
    【转存】Vue组件选项props
    eclipse -- git 显示修改历史 对比文件
    eclipse -- git 提示
    mysql -- 查询并插入
    git --eclipse -- 下载超时
    mysql -- 字符串长度
  • 原文地址:https://www.cnblogs.com/caihg/p/5227094.html
Copyright © 2020-2023  润新知