LeeJim/better-fe

关于事件绑定的一些知识

Opened this issue · 0 comments

前端开发无法避免的就是浏览器兼容问题,虽然我们现在几乎可以抛弃IE7甚至IE8,但是无法避免的是仍然有用户在使用这些远古时代的浏览器。因此面试大型互联网公司总会考察相关的知识。因此我现在分享一下我遇到的一个考题:

现在有一段HTML

<ul id="list">
  <li>a</li>
  <li>b</li>
  <li>c</li>
</ul>

点击li的时候alert弹出li里面的文本内容,离开ul时alert提醒。

注意,需要考虑性能和兼容性问题。

分析点击事件

首先,大家都知道的是,在IE下绑定事件是使用attachEvent的,而不是addEventListener,因此可以封装一个方法来绑定事件:

/**
 * @param {DOM} target 表示事件绑定的元素
 * @param {String} method 表示绑定的事件
 * @param {Function} handler 表示绑定的事件处理函数
 */
function addEvent(target, method, handler) {
  if (target.addEventListener) {
    target.addEventListener(method, handler, false);
  }
  else if(target.attachEvent) {
    target.attachEvent('on' + method, handler)
  }
 else {
    target['on'+method] = handler
  }
}

需要注意的是,使用attachEvent时,事件类型都是需要加个on前缀的。还有就是因为attachEvent是将事件绑定在冒泡阶段的,为了保持一致,所以使用addEventListener时,需指定第三个参数为false,否则就添加到事件捕获阶段了。

其次,不能给每个li绑定事件,可以利用事件的冒泡机制,故需把事件绑定到ul上而不是li上。

此时要拿到真正的li就要读取事件(event)的真实对象(target)了,这也是一个考察点:

  • 在IE上,事件(event)要需要通过window.event获取的。

  • 在IE上,事件对象(event target)的值是event.srcElement而不是event.target

因此绑定点击事件的完整代码是这样的:

var list = document.getElementById('list')

addEvent(list, 'click', function(event){
  event = event || window.event;
  var target = event.target || event.srcElement;
  
  alert(target.innerHTML)
})

分析鼠标移开事件

其实,这个才是这道题考察JavaScript能力的重点,因为通常情况下,我们就是使用mouseout事件就完了。然而这里隐藏了一个问题:就是当鼠标移入ul的子元素li时,也会触发mouseout事件的,所以这道题的重点就是考察面试者到底有没考虑到这个点。

然而考察并没有结束,此时又出现了一个考察点:就是如何获取鼠标移出时移到哪个元素了。

在现代浏览器(chrome,firefox,safari等等)上,我们直接用event.relatedTarget就可以直接获取;而在IE上则比较繁琐,mouseout事件有一个叫toElement的元素(顾名思义就是鼠标移到了哪个元素),mouseover事件则有一个叫fromElement元素。

因此,我们可以这么做:

 addEvent(list, 'mouseout', function(event){
  event = event || window.event;
  var t = event.relatedTarget || event.toElement;
  if(!list.contains(t)) {
    alert('!')
  }
})