1. 事件
JavaScript与HTML之间的交互是通过事件来实现的。事件就是文档或浏览器窗口中发生的一些特定的交互瞬间。
<div id="div1">我是一个div</div>
<button id="btn1">按钮1</button>
<button id="btn2" onclick="clickFun()">按钮2</button>
<script>
//1.在元素外部JS给元素绑定事件
var div = document.getElementById('div1');
var btn = document.getElementById('btn');
btn1.onclick = function(){
div.innerHTML = '点击按钮改变的';
div.style.height = '200px';
div.style.width = '200px';
div.style.backgroundColor = 'red';
}
//2.在元素内部给其绑定事件
function clickFun(){
console.log('我是btn2绑定的事件');
div.style.backgroundColor = 'green';
}
</script>
1.1. 事件三要素:
- 事件源:事件被触发的对象–>按钮对象
- 事件类型:如何触发?触发什么事件?例如鼠标点击,键盘按下等…
- 事件处理程序:通过一个函数赋值的方式
1.2. 执行事件的步骤:
- 获取事件源
- 注册事件(绑定事件)
- 采用函数赋值形式添加事件处理程序
1.3. 常用事件:
用户点击鼠标时、网页加载后、图线加载后、鼠标移动至元素上时、输入字段被改变时、HTML表单被提交时、用户敲击按键时······
2. 事件流
一个事件发生后,会在子元素和父元素之间传播(propagation)。这种传播分成三个阶段。
(1)捕获阶段:事件从window对象自上而下向目标节点传播的阶段;
(2)目标阶段:真正的目标节点正在处理事件的阶段;
(3)冒泡阶段:事件从目标节点自下而上向window对象传播的阶段。
2.1. 事件冒泡(IE事件流)
事件被定义为从最具体的元素(文档树中最深的节点)开始触发,然后向上传播至没有那么具体的元素
<div id="outer">outer
<div id="center">center
<div id="inner">inner</div>
</div>
</div>
<script>
var inner = document.getElementById('inner');
var center = document.getElementById('center');
var outer = document.getElementById('outer');
//三层都设置点击事件,若最内层触发,则三层都触发
inner.onclick = function(){
console.log('我是inner点击的');
};
center.onclick = function(){
console.log('我是center点击的');
}
outer.onclick = function(){
console.log('我是outer点击的');
}
</script>
在点击页面中的id为inner的div元素,click事件会以div#inner—>div#center—>div#outer—>body—>html—>document的顺序发生(由内向外)。
现在浏览器中的事件会一直冒泡到window对象
2.2. 阻止事件冒泡
DOM事件默认提供一个HTML DOM Event对象,代表事件的状态,如事件在其中发生的元素、键盘按键的状态、鼠标的位置、鼠标按钮的状态。
事件通常与函数结合使用,函数不会在事件发生前被执行。
直接在对应的方法中使用event.stopPropagation()
便可阻止事件冒泡
2.3. 事件捕获(Netscape事件流)
最不具体的节点应该最先收到事件,而最具体的节点应该最后收到事件,
事件捕获实际上是为了在事件到达最终目标前拦截事件。上个例子中的事件捕获的触发顺序document—>html—>body—>div(由外向内)
3. 事件处理程序
事件意味着用户或浏览器执行的某种动作。如单机(click)、加载(load)、鼠标悬停(mouserover)。为响应事件而调用的函数称为事件处理程序,事件处理程序名字以“on”开头。
3.1. HTML事件处理程序
特定元素支持的每个事件都可以使用事件处理程序的名字以HTML属性的形式来指定。此时属性的值必须是能够执行的JavaScript代码。如要在按钮被点击时执行某些JavaScript代码,可以使用以下HTML属性:
<button onclick="sonsole.log('Clicked')"></button>
点击这个按钮后,控制台会输出一条消息。这种交互能力是通过为onclick属性指定JavaScript代码值来实现的。
因为属性的值是JavaScript代码,所以不能在未经转义的情况下使用HTML语法字符,比如和号(&)、双引号(")、小于号(<)和大于号(>)。此时,为了避免使用HTML实体,可以使用单引号代替双引号。如果确实需要使用双引号,则要把代码改成下面这样:
<button onclick="console.log("Clicked")">222</button>
3.2. DOM0事件处理程序
在JavaScript中指定事件处理程序的传统方式是把一个函数赋值给(DOM元素的)一个事件处理程序属性。这也是在第四代Web浏览器中开始支持的事件处理程序赋值方法,直到现在所有现代浏览器仍然都支持此方法,主要原因是简单。要使用JavaScript指定事件处理程序,必须先取得要操作对象的引用。每个元素(包括window和document)都有通常小写的事件处理程序属性,比如onclick。只要把这个属性赋值为一个函数即可。
<script>
var btn = document.getElementById('btn');//先取得按钮引用
btn.onclick = function(){//再给onclick事件处理程序赋值一个函数
console.log('我被点击了');
console.log(this.id);//this指代触发点击事件的元素,使用this来引用元素本身 btn
}
//在JavaScript中将相应属性设置为null来移除
btn.onclick = null;//DOM0事件处理程序移除事件的方法
</script>
像这样使用DOMO方式为事件处理程序赋值时,所赋函数被视为元素的方法。因此,事件处理程序会在元素的作用域中运行,即this等于元素。
3.3. DOM2事件处理程序
DOM2 Event为事件处理程序的赋值和移除定义了两个方法。
这两个方法暴露在所有DOM节点上,它们接受3个参数:事件名、事件处理函数和一个布尔值,true表示在捕获阶段调用事件处理程序,false(默认)表示在冒泡阶段调用事件处理程序。
3.3.1. addEventListener()
<button id="btn">按钮</button>
<script>
var btn = document.getElementById('btn');
btn.addEventListener('click', function(){
console.log('我被点击了')
}, false);//false-冒泡阶段 true-捕获阶段
</script>
与DOM0方式类似,这个事件处理程序同样在被附加到元素的作用域中运行。使用DOM2方式的主要优势是可以为同一个事件添加多个事件处理程序(多个按顺序触发)。
3.3.2. removeEventListener()
通过addEventListener()添加的事件处理程序只能使用removeEventListener()并传入与添加时 同样的参数 来移除(意味着使用addEventListener()添加的匿名函数无法移除)。
<button id="btn">按钮</button>
<script>
var btn = document.getElementById('btn');
btn.addEventListener('click', function(){
console.log('我被点击了')
}, false);
btn.removeEventListener('click', function(){//移除失败,两个匿名函数并不相同
console.log('我被点击了')
}, false);
</script>
解决方案:
<button id="btn">按钮</button>
<script>
var btn = document.getElementById('btn');
var handler = function(){
console.log('我被点击了');
}
btn.addEventListener('click', handler, false);
btn.removeEventListener('click', handler, false);//移除成功
</script>
4. 事件对象
在DOM中发生事件时,所有相关信息都会被收集并存储在一个名为event的对象中。这个对象包含了一些基本信息,比如导致事件的元素、发生的事件类型,以及可能与特定事件相关的任何其他数据。例如,鼠标操作导致的事件会生成鼠标位置信息,而键盘操作导致的事件会生成与被按下的键有关的信息。所有浏览器都支持这个event对象,尽管支持方式不同。
注意:event对象只在事件处理程序执行期间存在,一旦执行完毕,就会被销毁。
4.1. 阻止默认事件发生
preventDefault()方法: 用于阻止特定时间的默认动作。如链接的默认行为就是在被单击时导航到href属性指定的URL或是修改表单提交的默认事件。
<a href="http://www.baidu.com">跳转</a>
<script>
var a = document.getElementsByTagName('a')[0];
a.onclick = function(event){
event.preventDefault();//阻止默认链接跳转事件发生
}
</script>
注意: 阻止事件默认行为与阻止事件冒泡是两个概念。
- 阻止事件默认行为:
event.preventDefault()
- 阻止事件冒泡:
return false
,在原生JavaScript中只会阻止默认行为,在jQuery中既阻止默认行为又防止对象冒泡。- W3C:
event.stopPropagation()
IE:event.cancelBubble = true
5. 事件代理(事件委托)
由于事件会在冒泡阶段向上传播到父节点,因此可以把子节点的监听函数定义在父节点上,由父节点的监听函数统一处理多个子元素的事件。
事件委托的根本原理:事件冒泡。
适用情况:当父级与子级有相同的事件处理程序需求时,绑定给子级即可。
<ul id="list">
<li id="item1">子列表1</li>
<li id="item2">子列表2</li>
<li id="item3">子列表3</li>
</ul>
<script>
var list = document.getElementById('list');
list.addEventListener('click', function(event){
var target = event.target;//触发事件的元素
console.log(target);
switch(target.id){
case 'item1':
target.innerHTML = 'SuZhou';
break;
case 'item2':
target.innerHTML = 'Coding';
break;
case 'item3':
target.innerHTML = 'Hi';
break;
}
});
</script>
只要可行,就应该考虑只给 document添加一个事件处理程序,通过它处理页面中所有某种类型的事件。
优点:
- document对象随时可用,无需等待加载时间。
- 只绑定在一个document对象上,节省了DOM引用,节省了时间。
- 节省整个页面内存,降低内存消耗,提升整体性能。
最适合使用事件委托的事件包括:click、mousedown、mouseup、keydown和keypress。
6. 事件类型
DOM3 Events定义了如下事件类型。
- 用户界面事件(UIEvent):涉及与BOM变互的通用浏览器事件。
- 焦点事件(FocusEvent):在元素获得和失去焦点时触发。
- 鼠标事件(MouseEvent):使用鼠标在页面上执行某些操作时触发。
- 滚轮事件(WheelEvent):使用鼠标滚轮(或类似设备)时触发。
- 键盘事件(KeyboardEvent):使用键盘在页面上执行某些操作时触发。
- 输入事件(InputEvent)
6.1. 用户界面事件(UIEvent)
- load
在window上当页面加载完成后触发,在窗套(<frameset>
)上当所有窗格(<frame>
)都加载完成后触发,在<img>
元素上当图片加载完成后触发,在<object>
元素上当相应对象加载完成后触发。
window.onload = function(){
console.log('onload');
}
- unload
当页面完全卸载后在window上触发,当所有框架都卸载后在框架集上触发,当嵌入的内容卸载完毕后在<object>
上触发。 - select()
在文本框(<input>
或textarea)上当用户选择了一个或多个字符时触发。
<input type="text" id="inp">
<script>
var inp = document.getElementById('inp');
inp.onselect = function(event){
console.log(event);
console.log(window.getSelection().toString());
}
</script>
- resize
在window或窗格上当窗口或窗格被缩放时触发。
<body onresize="myFun()">
<script>
function myFun(){
console.log(window.outerHeight, window.outerWidth);
}
</script>
</body>
- scroll
当用户滚动包含滚动条的元素时在元素上触发。<body>
元素包含已加载页面的滚动条。
大多数HTML事件与window对象和表单控件有关。
<div id="d1" style="width:100px; height:100px; border:1px solid black; overflow:auto">
111111111111111我是div标签我是div标签我是div标签我是div标签我是div标签
</div>
<script>
var d1 = document.getElementById('d1');
d1.onscroll = function(){
console.log('onscroll');
}
</script>
6.2. 焦点事件(FocusEvent)
- blur
当元素失去焦点时触发。这个事件不冒泡,所有浏览器都支持。 - focus
当元素获得焦点时触发。这个事件不冒泡,所有浏览器都支持。
<input type="text" id="inp1">
<script>
var inp1 = document.getElementById('inp1');
//失去焦点触发
inp1.onblur = function(){
console.log('失去焦点');
console.log(this.value);
}
//获得焦点触发
inp1.onfocus = function(){
console.log('获得焦点');
}
</script>
- focusin
当元素获得焦点时触发。这个事件是focus的冒泡版。 - focusout
当元素失去焦点时触发。这个事件是blur的冒泡版。
6.3. 鼠标事件(MouseEvent)和滚轮事件(WheelEvent)
- click
在用户单击鼠标主键(通常是左键)或按键盘回车键时触发。这主要是基于无障碍的考虑,让键盘和鼠标都可以触发onclick事件处理程序。 - dblclick
在用户双击鼠标主键(通常是左键)时触发。这个事件不是在 DOM2 Events 中定义的,但得到了很好的支持,DOM3 Events 将其进行了标准化。 - mousedown
在用户按下任意鼠标键时触发。这个事件不能通过键盘触发。 - mouseenter
在用户把鼠标光标从元素外部移到元素内部时触发。这个事件不冒泡,也不会在光标经过后代元素时触发。mouseenter 事件不是在 DOM2 Events 中定义的,而是 DOM3 Events中新增的事件。 - mouseleave
在用户把鼠标光标从元素内部移到元素外部时触发。这个事件不冒泡,也不会在光标经过后代元素时触发。mouseleave 事件不是在 DOM2 Events 中定义的,而是 DOM3 Events中新增的事件。 - mousemove
在鼠标光标在元素上移动时反复触发。这个事件不能通过键盘触发。 - mouseout
在用户把鼠标光标从一个元素移到另一个元素上时触发。移到的元素可以是原始元素的外部元素,也可以是原始元素的子元素。这个事件不能通过键盘触发。 - mouseover
在用户把鼠标光标从元素外部移到元素内部时触发。这个事件不能通过键盘触发。 - mouseup
在用户释放鼠标键时触发。这个事件不能通过键盘触发。 - mousewheel
鼠标滚轮事件
6.4. 键盘事件(KeyboardEvent)和输入事件(InputEvent)
- keydown:用户按下键盘上某个键时触发,而且持续按住会重复触发。
- keypress:用户按下键盘上某个键并产生字符时触发,而且持续按住会重复触发。
- keyup:用户释放键盘上某个键时触发。
- textInput:在文本插入文本框之前会触发textInput事件。
<input type="text" id="inp1">
<script>
var inp1 = document.getElementById('inp1');
// 键盘输入事件 必须使用DOM2级事件
inp1.addEventListener('textInput', function (event) {
console.log(event);
}, false)
</script>