事件模型
当满足以下两个条件,就需要处理事件的冲突:
- 子元素和祖先元素之间都有监听 (不管子元素的布局位置是不是在祖先元素内)
- 并且是相同的事件类型 (如果子元素是'click'而祖先元素是'keydown',则不会被波及)
从前网景和微软不对付,他们的浏览器一个采用捕获模型一个采用冒泡模型.后来W3C将两种模型都写进标准,开发者可自由选择,但是事件的默认参数采用微软的冒泡模型.
捕获: 子元素上监听到事件,那么从最上层的祖先元素依次向下触发事件监听函数,直到子元素.div.addEventListener('click',functino(){},true)第三个参数为true为捕获
冒泡: 子元素上监听到事件,从子元素开始依次向祖先元素触发事件监听函数.无第三个参数或第三个参数为false,为冒泡.
先捕获后冒泡 可以再一个元素上安装两个监听来获得两个模型,但是浏览器会依照有先捕获然后冒泡的顺序
阻止冒泡 所有冒泡都能阻止不需要冒泡波及到祖先的时候,那么可以给事件监听函数来这么一句e.stopPropagation
事件委托
事件委托指把A元素的监听,委托给会受到A波及的B元素上,这样做可以减少内存使用.例如,可以将多个子元素的相同的监听函数安装在共同的父元素上,利用冒泡的机制共用一个父元素上的监听函数.还可以监听动态生成的元素.例如,给一个还没创建的子元素它的父元素添加监听
jQuery实现事件委托
- on:
$('.parent').on('click', 'a', function () { console.log('click event on tag a'); }),.parent 元素之下的 a 元素的事件代理到 $('.parent') 之上,只要在这个元素上有点击事件,就会自动寻找到 .parent 元素下的 a 元素,然后响应事件 - .delegate:
$('.parent').delegate('a', 'click', function () { console.log('click event on tag a'); }),同上,并且还有相对应的 $.delegate 来删除代理的事件;
局限性
当然,事件委托也是有一定局限性的;
比如 focus、blur 之类的事件本身没有事件冒泡机制,所以无法委托;
mousemove、mouseout 这样的事件,虽然有事件冒泡,但是只能不断通过位置去计算定位,对性能消耗高,因此也是不适合于事件委托的
事件信息
e.targret是操作元素,e.currenTarget是监听元素,一个触发事件的元素,一个是绑着该事件的元素
阻止默认事件
有些事件可以阻止有些不能.e.cancelable表示事件默认行为是否可以阻止, 若可采用e.preventDefault();阻止
如何阻止滚动?首先Scroll事件为不可阻止默认事件,PC应采用
- 阻止wheel事件
overhidden隐藏滚动条
手机采用
- 阻止touchstart事件
overhidden隐藏滚动条
上述方法无法阻止JS的scrollTop(x,y)方法
自定义事件
自定义一个事件任意设置他的属性.e.cancelable
event = new Event(typeArg, eventInit)