1 JavaScript DOM事件
DOM事件模型是什么:指的是冒泡和捕获
DOM事件流是什么:捕获阶段 -> 目标阶段 -> 冒泡阶段
1.1 事件流
参考文章:《js之事件冒泡和事件捕获详细介绍》
事件流分为两种:事件冒泡和事件捕获
事件冒泡:事件最开始由最具体的元素(文档中嵌套层次最深的那个节点)接收,然后逐级向上传播至最不具体的那个节点(文档),如:
事件捕获:最不具体的节点应该更早接收到事件,而最具体的节点最后接收到事件,如:
二者综合起来就是DOM事件事件流了:
1.2 事件属性的绑定
1.2.1 HTML事件处理程序
HTML事件处理程序是指直接在HTML元素标签中添加如onclick = funcA()
属性,这样的缺点是:HTML和JS代码紧密的耦合在一起
1.2.2 DOM 0级事件处理程序
形如element.onclick = function(){}
;删除事件属性element.onclick = null
。优点:简单,跨浏览器
1.2.3 DOM 2级事件处理程序
DOM2级事件定义了两个方法:用于处理指定和删除事件处理程序的操作,分别是addEventListener()
和 removeEventListener()
,与DOM 0级不同的是DOM 1级重复定义的事件,不会被新的事件替换掉,而是按先后顺序执行。
addEventListener()
和removeEventListener()
都接受三个参数,分别是:事件名(如click
),事件函数以及布尔值(数值为true
时,表示在捕获阶段调用;数值为false
时,表示在冒泡阶段调用)如:
<input type="button" value="按钮" id="btn3">
<script>
var btn3 = document.getElementById('btn3');
btn3.addEventListener('click',showMessage,false);
btn3.addEventListener('click',function(){
alert(this.value);
},false)
btn3.removeEventListener('click',showMessage,false)
</script>
IE9前的版本并不支持
addEventListener()
和removeEventListener()
,它们使用attachEvent()
和detachEvent()
,attachEvent()
和detachEvent()
接收两个参数,分别是事件名和事件函数
为此,可以编写一个小组件处理兼容问题:
var eventUtil = {
addHanler:function(element,type,handler){
if (element.addEventListener) {
element.addEventListener(type,handler,false);
} else if (element.attachEvent){
element.attachEvent(type,handler);
} else {
//使用DOM 0级事件处理程序
element['on' + type] = handler;
}
}
removeHandler:function(element,type,handler){
if (element.removeEventListener){
element.removeEventListener(type,handler,false);
} else if (element.detachEvent) {
element.detachEvent(type,hanlder);
} else {
element['on' + type] = handler
}
}
}
//跨浏览器添加事件处理程序;
eventUtil.addHandler(btn3,'click',showMessage);
1.3 事件对象
在触发DOM上的事件时都会产生一个对象event
,该对象有以下属性及方法:
type
:获取事件类型target
:获取事件目标event.currentTarget
:返回绑定事件的元素stopPropagation()
:停止事件冒泡preventDefault()
: 阻止事件的默认行为
IE有另一个事件对象window.event
,该对象有以下属性及方法:
type
:获取事件类型srcElement
:获取事件目标cancleBubble()
:停止事件冒泡returnValue = false
: 阻止事件的默认行为
为此,可以编写一个小组件处理兼容问题:
function showMes(event){
//非IE用event,IE8以下用window.event;
event = event || window.event;
//事件目标兼容;
var ele = event.target || event.srcElement;
//兼容阻止事件冒泡;
if(event.stopPropagation){
event.stopPropagation();
}else{
event.cancleBubble();
};
//兼容取消事件默认行为;
if(event.preventDefault){
event.preventDefault();
}else{
event.returnValue = false;
}
}
由于不同的浏览器绑定事件的代码都不太一样,所以用jQuery来写代码,就屏蔽了不同浏览器的差异,我们总是编写相同的代码。
2 jQuery 对象事件
2.1 绑定事件
2.1.1 on()
方法
与原装的JavaScript直接使用事件属性绑定函数不同,jQuery对象使用的是on
方法,on
方法用来绑定一个事件,我们需要传入事件名称和对应的处理函数,如:
$a.on("click",function(){
alert("Hello");
});
还有一种更为简便的方法:
$a.click(function(){
alert("Hello");
});
2.1.2 one()
方法
使用one()
方法绑定的事件函数都只能运行一次
$a.one("click",function(){
alert("Hello");
});
event.preventDefault()
方法阻止元素发生默认的行为(常用于点击提交按钮时阻止对表单的提交),值得注意的是使用这个方法,请记得在定义事件函数的时候添加event
参数(jQuery方法)
2.1.3 toggle()
方法
$("#abc").toggle(fn1,fn2,fn3,fn4...)
toggle()
方法用于模拟鼠标连续单击事件,当第一次点击时执行函数fn1,第二次执行函数fn2,第三次fn3,等等一次触发,直到最后循环。
2.2 比较常用的事件属性
2.2.1 鼠标事件
- blur:失焦
- focus:聚焦
- click::鼠标单击时触发;
- dblclick:鼠标双击时触发;
- mouseover:鼠标进入匹配元素时触发,而且如果进入匹配元素的子元素,也会触发
- mouseout:鼠标离开匹配元素时触发,而且如果离开匹配元素的子元素,也会触发
- mouseenter:鼠标进入匹配元素时触发,如果进入匹配元素的子元素,不会触发
- mouseleave:鼠标离开匹配元素时触发,如果离开匹配元素的子元素,不会触发
- hover:鼠标进入和退出时触发两个函数,相当于mouseenter加上mouseleave
2.2.2 其它事件
- change:当
<input>
、<select>
或<textarea>
的内容改变时触发; - submit:当
<form>
提交时触发; - ready:当页面被载入并且DOM树完成初始化后触发,相当于
window.onload()
,区别在于window.onload()
会把所有的文档资源都下载好才执行,而ready
只需准备好DOM文档就可以了
其中要说明的是ready
仅仅作用于document对象,即要作用于$(document)
,ready
事件除了上述那样的绑定方法外,还可以简化成这样绑定:
$(function () {
// init...
});
重复的绑定
ready
事件,他们不会失效而是会依次进行,普通事件也一样
2.3 取消事件绑定
一个已被绑定的事件可以解除绑定,通过off('click', function)
实现,要注意的是这方法并不能解除匿名函数,也就是说要建立取消事件绑定的jQuery对象其相应的事件函数一定要命名,当然为了实现移除效果,也可以使用off('click')
一次性移除已绑定的click事件的所有处理函数。
function hello() {
alert('hello!');
}
a.click(hello); // 绑定事件
// 10秒钟后解除绑定:
setTimeout(function () {
a.off('click', hello);
}, 10000);
/* 或者这样 */
setTimeout(function () {
a.off('click');
}, 10000);
如果直接调用
a.off()
的形式,即其所有的事件函数都会被删除
2.4 事件触发条件
一个需要注意的问题是,事件的触发总是由用户操作引发的。但如change
事件,其实是可以使用代码直接触发的,这样一来可以少写点代码,如:
var input = $('#test-input');
input.change(function () {
console.log('changed...');
});
input.change();//直接调用
2.5 triggerHanlder()
使用以上形式激活事件是会同时激活浏览器的默认操作的,如focus
事件,触发事件函数的同时,也会是元素本身得到焦点
如果只想触发事件,而不想执行默认浏览器默认操作,就可以使用trigglerHanlder()
方法:
$("input").triggleHandler("focus");
2.6 题目加深印象
<!DOCTYPE html>
<html>
<head>
<title>test</title>
<script type="text/javascript" src="jquery-3.2.1.js"></script>
<script type="text/javascript">
$(function(){
var $allinput = $("input[name=lang]");
var $selectall = $("label.selectAll input");
var $selectalltxt = $("span.selectAll");
var $deselectalltxt = $("span.deselectAll");
var $a = $("a.invertSelect");
$allinput.prop("checked",false);
$deselectalltxt.hide();
function tof () {
for (var i=0;i<5;i++) {
if ($allinput[i].checked) {
} else {
return false;
}
}
return true;
}
$selectall.click(function() {
if (!tof()) {
$allinput.prop("checked",true);
$selectalltxt.hide();
$deselectalltxt.show();
$selectall.prop("checked",true);
}else {
$allinput.prop("checked",false);
$deselectalltxt.hide();
$selectalltxt.show();
$selectall.prop("checked",false);
}
})
/* change不是click */
$allinput.change(function(){
if (tof()) {
$deselectalltxt.show();
$selectalltxt.hide();
$selectall.prop("checked",true);
}
else {
$deselectalltxt.hide();
$selectalltxt.show();
$selectall.prop("checked",false);
}
})
$a.click(function(){
for (var j=0;j<5;j++) {
if ($allinput[j].checked) {
$allinput[j].checked=false;
} else {
$allinput[j].checked=true;
}
}
$allinput.change();//调用时间函数,注意如果上面写click时间,就无法调用了调用
})
})
</script>
</head>
<body>
<div id="test-div">
<form id="test-form" action="test">
<legend>请选择想要学习的编程语言:</legend>
<fieldset>
<p><label class="selectAll"><input type="checkbox"><span class="selectAll">全选</span><span class="deselectAll">全不选</span></label> <a href="#0" class="invertSelect">反选</a></p>
<p><label><input type="checkbox" name="lang" value="javascript"> JavaScript</label></p>
<p><label><input type="checkbox" name="lang" value="python"> Python</label></p>
<p><label><input type="checkbox" name="lang" value="ruby"> Ruby</label></p>
<p><label><input type="checkbox" name="lang" value="haskell"> Haskell</label></p>
<p><label><input type="checkbox" name="lang" value="scheme"> Scheme</label></p>
<p><button type="submit">Submit</button></p>
</fieldset>
</form>
</div>
</body>
</html>
这里还有一个简化版
<!-- 布尔值的赋值很奇妙的,理解原由会让事情方便简洁许多 -->
<script type="text/javascript">
$(function(){
var $allinput = $("input[name=lang]");
var $selectall = $("label.selectAll input");
var $selectalltxt = $("span.selectAll");
var $deselectalltxt = $("span.deselectAll");
var $a = $("a.invertSelect");
$allinput.prop("checked",false);
$deselectalltxt.hide();
/* 绑定单个选项的改变事件 */
$allinput.change(function(){
var $judge = ($("input[name=lang]:checked").length==5);
$selectall.prop("checked",$judge);
if ($judge) {
$selectalltxt.hide();
$deselectalltxt.show();
} else {
$selectalltxt.show();
$deselectalltxt.hide();
}
})
/* 全选事件 */
$selectall.click(function () {
let isAllSelected = $selectall.is(':checked');//使用全选选项的勾选与否判断是否全选
$allinput.prop('checked', isAllSelected);
// 手动调用
$allinput.change();
})
/* 反选事件 */
$a.click(function(){
$allinput.map(function(){
var mid = this.checked;//对应的this指向dom对象,保存原始的选项
this.checked=!mid;//改变布尔值
})
$allinput.change();
})
})
</script>