您现在的位置是:首页 > 技术学习 > javascript 网站首页 技术学习 javascript
JS事件绑定、冒泡/捕获、常见的兼容处理、委托、阻止默认行为和冒泡
- 技术学习
- 2019-05-16
- 1133已阅读
- 5
1. 事件绑定
我们常见的事件一般是类似 obj.onclick = function () {}
; 这种,这种情况下,如果给同一个obj写同一个事件,那后面写的事件会把之前的事件给覆盖掉,只执行后加的事件函数。
而事件绑定不会出现这种情况,用事件绑定方式给同一个对象加同一个事件,多次绑定的事件对应的事件函数都会执行。
IE8及以下:
事件绑定:attachEvent("on"事件名称,事件函数);
解除绑定:detachEvent("on"事件名称,事件函数);
ps: 上面的'"on"事件名称'是指:类似onclick、onmouseup这种 on+事件名称 的写法。
默认是冒泡阶段执行。
Dom主流浏览器:
事件绑定:addEventListener(事件名称,事件函数,捕获/冒泡);
解除绑定:removeEventListener(事件名称,事件函数,捕获/冒泡);
ps: 这里的'事件名称'是指:类似click、mouseup这种不加'on',直接写事件名的写法。
'捕获/冒泡'是指:绑定的事件是在捕获还是冒泡阶段执行,该值为布尔值,
捕获为true,冒泡为false,默认是false冒泡。
兼容方法:
if (x.addEventListener) { // 所有主流浏览器,除了 IE 8 及更早 IE版本
x.addEventListener("click", myFunction);
} else if (x.attachEvent) { // IE 8 及更早 IE 版本
x.attachEvent("onclick", myFunction);
}
注:为了移除方便,可将事件函数赋值给一个变量,然后在绑定时候,将该变量写进里面,这样移除时可以直接指定这个变量。
<script type="text/javascript">
// 不用事件绑定时
var oDiv = document.getElementById("mydiv");
oDiv.onclick = function () {
alert(1);
};
oDiv.onclick = function () {
alert(2);
};
// 点击只会弹2;
</script>
<script type="text/javascript">
// 事件绑定时
var oDiv = document.getElementById("mydiv");
var myFnA = function () {
alert("a");
};
var myFnB = function () {
alert("b");
};
oDiv.addEventListener("click", myFnA);
oDiv.addEventListener("click", myFnB, true);
// a和b都能弹出来,先弹a;
// oDiv.removeEventListener("click", myFnB, true);
// 不能弹出b,解除事件成功
// oDiv.removeEventListener("click",myFnB,false);
// 仍能弹出b,可见解除绑定时需要针对一样的true或false进行解除。
</script>
2. 冒泡和捕获
冒泡:
事件由里到外
传递。当一个dom节点发生事件,这个事件向父级方向传递,直到达到最顶层document(有的是window)。
也就是说,该元素的父级也能监听的到该事件的,如果父级恰好对该事件有执行函数,那么是会触发这个函数的。执行顺序是从里到外。
捕获:
事件由外到里
传递。当一个dom节点发生事件,这个事件从顶层document(有的是window)向该dom节点方向传递,执行顺序是从外到里。
注:
W3C中,浏览器对事件的处理是先进行捕获,再进行冒泡。事件先从顶层一级一级到事件源,然后再一级一级到顶层。
但是,针对事件源(该事件最里层的那个节点),捕获和冒泡执行顺序是谁写在前面先执行谁(事件源不分捕获冒泡先后顺序,当做普通绑定事件对待,按绑定先后执行)。
<div id="mydiv">
<div id="mydiv2"></div>
</div>
<script type="text/javascript">
var oUl = document.getElementById('myul');
var oLi = document.getElementById('li1');
oUl.addEventListener('click',function(){
alert(0);
return false;
},true);
oLi.addEventListener('click',function(){
alert(1);
});
// 给父子div绑定点击事件,分别在他们捕获和冒泡阶段触发。
var oDiv = document.getElementById("mydiv");
var oDiv2 = document.getElementById("mydiv2");
oDiv.addEventListener("click",function () {alert("a");},false);
oDiv.addEventListener("click",function () {alert("b");},true);
oDiv2.addEventListener("click",function () {alert("c");},false);
oDiv2.addEventListener("click",function () {alert("d");},true);
/*
点击oDiv2,弹出顺序是b、c、d、a;
由a、b的顺序可知:是先捕获,再冒泡,
c、d的顺序可知:
事件源是oDiv2(该事件最里层是oDiv2)
所以针对oDiv2的捕获和冒泡,不是先执行捕获,而是谁写在前面先执行谁。
*/
</script>
3. 常见的兼容处理
3-1 ev和event
e = ev || window.event;
或者 e = ev || event;
或者 e = arguments[0] || window.event;
由于不同浏览器解释js代码方式不同,当我们把触发的事件对象赋予变量e的时候,一些浏览器像火狐,是直接把事件对象作为第一个参数传进去就行,我们可以把参数写作ev,也可以用arguments[0];一些浏览器像IE、chrome这种,事件对象的定义是window.event,因为所有对象都是window的属性,因此window.event == event;
<script type="text/javascript">
function test1 (ev) {
var e = ev || window.event;
};
function test2 (ev) {
var e = ev || event;
};
function test3 () {
var e = arguments[0] || window.event;
// js函数,即使不传参数,但是还是有一个arguments数组用来入参,
};
</script>
3-2 获取页面的一些值时的兼容
document.documentElement.属性 // chrome不支持
document.body.属性 // chrome能识别
<script type="text/javascript">
var top = document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop;
// 或者
var scrollT = document.documentElement.scrollTop || document.body.scrollTop;
</script>
类似这样获取方式的属性还有:
- clientWidth(网页可视区宽)、
- clientHeight(网页可视区高)、
- scrollWidth(网页正文全文宽)、
- scrollHeight(网页正文全文高)、
- scrollTop(可视区到网页顶端的距离,及网页被卷去的高)、
- scrollLeft(可视区到网页左端的距离,及网页被卷去的宽)
3-3 获取最终样式的兼容
我们用js的style获取的样式只能获取标签元素的行间样式,获取不到非行间样式。如果元素样式没用行间样式定义,那要怎么获取元素的样式呢?
IE下:
obj.currentStyle.属性; // ie9以下
主流浏览器:
getComputedStyle(obj,null).属性;
// 火狐、chrome、ie9以上。第二个参数可为任意值,一般写null就行。
<script type="text/javascript">
function getStyle(obj,attr){
if (obj.currentStyle) {
return obj.currentStyle[attr];
} else {
return getComputedStyle(obj,null)[attr];
};
};
</script>
4. 事件委托
事件委托
:利用冒泡的原理,把事件加在父级上来触发执行效果。
事件源
:不管在哪个事件下,操作的对象就是事件源。
好处:1.提高性能
2.后添加进来的元素也能加上事件
原理
:给父元素添加事件监听器。当有事件触发监听器时,检查事件的来源,然后根据不同的事件源来执行相应的代码。
兼容写法:
IE下:
e.srcElement
标准下:
e.target这样获取到的是
触发事件的那个对象
,
事件中this
指向:绑定事件的父元素。
实际使用中,可以根据触发事件的对象的一些特征来进行判定,从而执行相应的代码。
例:
可以判断nodeName;获得的是该对象元素标签的大写形式(为string格式,使用时需要注意),可以用toLowerCase(); 转化为小写后再判断。
也可以判断其他的特征,如className、其他属性等
示例代码:
<div id="mydiv">
<ul>
<li></li>
<li></li>
</ul>
<span class="myspan"></span>
</div>
<script type="text/javascript">
var oDiv = document.getElementById('mydiv');
oDiv.addEventListener('click',function (e) {
var e = e || event;
var target = e.srcElement || e.target;
if (target.nodeName == 'LI') {
alert('点击了li');
console.log(target); // 该li对象
console.log(e.currentTarget);
// 绑定事件的div对象,注意这里用的是e,(注意currentTarget和target的区别)
console.log(this); // 绑定事件的div对象
} else if (target.className == 'myspan') {
alert('点击了span');
console.log(target); // 该span对象
console.log(this);// 绑定事件的div对象
};
});
</script>
5. 阻止默认行为和冒泡
我们有时候会遇见这样的问题:
- 一个submit按钮,点击会提交表单数据,但是我们不希望什么数据都能够提交,想进行一些前端校验,合法数据才能提交,不合法数据不让提交。那怎样才能阻止不合法数据提交呢?这时候就需要阻止提交行为的发生。
- 有时候当我们给父子元素都加了点击事件,但我们不希望点击子元素时父元素的点击事件也触发。这时候我们需要阻止冒泡行为。
有的标签具有默认行为,比如a标签的跳转,submit的提交,这些行为在点击时会发生,我们可以在点击事件中进行阻止。
阻止默认行为:
- 普通写法:return false;(高版本浏览器都支持)
注:这句话要写在自己代码的后面。- 兼容写法:
IE: e.returnValue = false;
w3c: e.preventDefault();
<a id="mya" href="http://www.baidu.com">百度</a>
<script type="text/javascript">
var oA = document.getElementById('mya');
oA.addEventListener('click',function (e) {
var e = e || event;
if (e.preventDefault) {
// 阻止默认浏览器动作(W3C)
e.preventDefault();
} else {
// 阻止函数器默认动作(IE)
e.returnValue = false;
};
});
</script>
阻止冒泡:
IE方法:e.cancelBubble = true;
w3c方法:e.stopPropagation();
<div>
<div id="mydiv">子div</div>
<div>
<script type="text/javascript">
var oDiv = document.getElementById('mydiv');
oDiv.addEventListener('click',function(e) {
e = e || event;
if (e.stopPropagation) {
// W3C阻止冒泡方法
e.stopPropagation();
} else {
// IE阻止冒泡方法
e.cancelBubble = true;
};
};
</script>
平常使用过程中,如果用到阻止默认行为和冒泡较多,可以将他们封装成函数,
<script type="text/javascript">
function preventDefa(e){
var e = e || window.event;
if (e.preventDefault) {
// 阻止默认浏览器动作(W3C)
e.preventDefault();
} else {
// 阻止函数器默认动作(IE)
e.returnValue = false;
};
};
//阻止冒泡事件的兼容性处理
function stopBubble(e) {
var e = e || window.event;
if (e.stopPropagation) {
// W3C阻止冒泡方法
e.stopPropagation();
} else {
// IE阻止冒泡方法
e.cancelBubble = true;
};
};
</script>