手写事件代理函数 (Delegated function)

‘手写 ’ 这个词 ,面试是不是听过无数遍呢 !

今天我们来手写一个这样的事件委托函数 =》

function( parent, selector, type ,  handle)  {}

你需要传递的参数分别是:

parent: 事件绑定的父级

selector: 选择器,

type:  事件类型

handle: 事件处理函数

 

写之前 先了解一下事件委托的概念:     

    它是通过事件冒泡机制,

       即子元素上触发的事件会冒泡到父级上, 即父级也会触发该类型的事件,

       通过父级触发的事件拿到事件源对象e.target  就可以 知道 真正触发事件的元素是什么。

 

举个例子, 一个ul 下面有 1000 个  li   , 我们 要给  li  绑定  点击事件 , 如果给每个li都绑定一个

点击事件  会  大量占用 内存   , 不利于性能优化, 这种情况下 我们 只需要在ul上绑定一个点击事件,

通过class 或者 id 来识别每个li ,  这样就大大减少了事件注册, 而且 再 有新增的li时 我们也无需再去注册点击事件

 

我们来写个小demo

HTML:

<ul id="parent">
    <li>1</li>
    <li>2</li>
    <li>3</li>
</ul>

css:

.active{
    background-color: green;
}

js:

const parent = document.getElementById('parent');
function changeColor() {
  if (this.classList.contains('active')) {
  this.classList.remove('active')
  } else {
  this.classList.add('active');
  }
 } 

function delegate(parent, selector, type, handle) { }
delegate(parent,
'li', 'click',changeColor);

我们要实现点哪个li  , 哪个li就变成原谅色, 再次点击取消。并 做 浏览器的兼容

我们开始写 delegate函数:

function matchSelector(target, selector) {
    if (selector.match(/^#/g)) { // 匹配以#开头的字符串
        return target.id === selector.slice(1); // 截取#后面的字符串
    }
    if (selector.match(/^\./g)) {  // . 要转义,匹配以点开头的字符转
        return target.classList.contains(selector.slice(1))
    }
    return target.nodeName.toLowerCase() ===  selector; // 匹配标签
}
function delegate(parent, selector, type, handle) {
    if (parent.addEventListener) {
        parent.addEventListener(type, eventFn, false)
    } else {   // 兼容老IE
        parent.attachEvent('on' + type, handle)
    }
    function eventFn(e) {
        const event = e || window.event;
        const target = event.target || event.srcElement;// 兼容老IE
        if (matchSelector(target, selector)) {
            if (handle) {
                handle.call(target, e); // 让handle执行时的this指向target
            }
        }
    }
}

 

 效果:

 

 

 

           

posted @ 2019-04-16 18:31  初心,你好吗  阅读(760)  评论(0编辑  收藏  举报