事件基础
常见的事件
mouseover与mouseout
表示鼠标移入和移出,与mouseenter与mouseleave不同的是,后者没有冒泡。也就是在父元素上绑定了事件,子元素上不会有事件。
click
点击事件
dblclick
双击鼠标事件
blur与foucs
失去焦点与焦点事件。可以用在表单、链接和window上。
不要在用户填完一个表单失去焦点的时候验证表单。可以用change事件来代替它(当用户改变了表单的内容时验证)。但是最好的方法是用onsubmit。
change
用户在改变了表单域的值的时候触发。对于下拉选择框来说,当用户选择了任意一个选项就立即触发该事件。对于复选框和单选框来说,当用户选中或取消选中它的时候就触发该事件。对于文本输入框来说,当用户改变了它的内容的时候且失去焦点的时候就触发。
contextmenu
就是在页面上点击右键时触发,这个事件通常用在禁用上下文菜单来禁止查看源码。
load与unload
当页面完全加载后就会触发load事件
。用在window对象上,此外load事件还可以用在图片上,等到图片完全加载完之后就会触发load事件。
readystatchange
通常用在ajax上。
submit
通常用在用户提交表单的时候被触发。只有当按钮被激活的时候才会提交。
resize
用户在改变浏览器窗口的大小的时候触发。只对window对象可用。
scroll
用户在滚动某块内容的时候触发。不管用户是拖拉滚动条还是使用方向键还是鼠标滚轮。scroll事件对任何能够产生滚动条的元素可用。
textInput
当用户在可编辑区域输入字符的时候就会触发该事件。
事件处理器
一旦你决定用哪个事件,你需要告诉浏览器当事件发生时运行哪个函数。这就要注册事件处理程序。
当用element.onclick=m时,注意m函数没有括号。
也可以用匿名函数。
例如:
window.onload=init;
function init(){}
最常用的就是:
x.addEventListener('click',doThis,false)
移除的话就是:
x.removeEventListener('click',doThis,false)
removeEventListener和addEventListener接受相同的参数。缺点就是这种写法移除事件处理函数的时候必须提供函数的名字。而上面的写法就不必(btn.onclick=null)。这就意味着不能使用匿名函数。
var btn=document.getElementById('myBtn');
btn.addEventListener('click',function(){
alert('this.id')
},false)
btn.removeEventListener('click',function(){
alert(this.id)
},false)
虽然看似传入了相同的参数,但是,实际上第二个参数与前面的是完全不同的参数。
var btn=document.getElementById('myBtn');
var handler=function(){}
btn.addEventListener('click',handler,false);
btn.removeEventListener('click',handle,false)
这样就传入了相同的参数。通常用false而不用true。
事件流
假设你有一个<div>
,它包含了一个<form>
,里面又有一个表单。它们都有一个onclick
事件。当点击表单的时候,<div>
和 <form>
的事件处理程序会被触发么?。答案是肯定的,如果有一个事件发生,而有多个事件处理程序,它们都会被触发。但是哪个先触发,取决于是用了事件捕获还是事件冒泡。
事件冒泡和事件捕获
事件从它的目标事件(用户点击的事件)开始,触发目标的事件处理程序,然后沿着文档树逐级冒泡,直到document元素为止。对于每个遇到的HTML元素,它都会触发相关的事件处理程序。因此<div>
和<form>
的事件处理程序都会被触发。
而事件捕获刚刚相反,它会先触发文档的一级,沿着文档树向下游历,直到事件的目标为止。对于每个遇到的HTML元素,它都会触发相关的事件处理程序。
界面事件如submit和change事件没有冒泡。
在w3c模型中事件冒泡和事件捕获都会存在。当一个事件触发时,先被文档捕获,然后沿着文档向下游历,直到事件目标为止。这叫捕获阶段。到达目标阶段后冒泡就开始,事件沿着原路反方向游历,直到文档为止。每个事件处理程序都是针对其中一种过程设置的。true代表是捕获,false为冒泡。
事件对象
当事件发生的时候就会自动创建这个对象。而且它包含该事件的各种有用的信息,比如目标对象、事件类型、鼠标位置、用户按下的按键等。
event对象,可以用e来表示。当然也可以随意给它命名。
event对象的type属性包含着事件类型。
event对象的了stopPropagation()方法用于取消事件传播。
event对象的preventDefault属性取消事件的默认行为,只有cancelable属性设置为true的事件才能使用preventDefault来取消其默认行为。
target属性包含着目标对象。即事件究竟发生在哪个元素上,而不是绑定事件的元素。而this指的是绑定事件处理程序的元素。
鼠标的位置需要知道鼠标相对于document的位置。就是event的pageX和pageY属性或者clientX和clienY属性。
目标对象的eventPhase属性用于确定事件正位于事件流的哪个阶段。捕获阶段,eventPhase等于1,事件处理程序处于目标对象上,则等于2,如果是在冒泡阶段调用的事件处理程序,则等于3.
易错
function test(){
this.style.backgroundColor='red'
}//错误。this总是指向方法被调用的那个对象,在这里函数test被window对象调用。所以this指向的是window.任何函数都可以看做是js的全局对象(window)的一个方法。而且this必须封闭在一个函数中才有用。
x.onclick=function(){
test()
}//错误。当用户点击x时候,事件处理程序调用test()。此时该函数是通过全局对象来调用的所以this指向的是window。
x.addEventListener('click',function(){test()},false);//错误。原因同上。
何时使用this,何时使用target?
一般来说,当注册同样的事件处理程序到许多元素上或者想要直接调用该事件处理程序的时候this是有用的。
当你依赖于事件冒泡使得事件沿文档树由下向上传播的时候,target是有用的。
实例
当点击的时候出现''clicked',当移入的时候背景颜色变为红色。当移出的时候背景颜色为默认值。
var btn=document.getElementById('myBtn')
var handler=function(event){
switch(event.type){
case 'click':
alert('Clicked');
break;
case 'mouseover':
event.target.style.background='red';
break;
case 'mouseout':
event.target.style.background='';
break;
}
}
btn.onclick=handler;
btn.onmouseover=handler;
btn.onmouseout=handler;
事件委托
指定一个事件处理程序就可以管理某一类型的所有事件。事件委托用到了事件冒泡。例如,我们可以为整个页面指定一个onclick事件,而不必为每个元素设置单击事件。
也可以为document对象添加一个特定的事件。有如下优点:
- document可以很快就会访问。只要可单击的元素呈现在页面上,就可以立即具备适当的功能。
- 在页面上设置事件处理程序的时间减少。
- 整个页面所占的内存减少。
移除事件处理程序应用
有这样一个需求当点击按钮的时候按钮消失变成一条网络消息。但是如果事件绑定在按钮上,当按钮消失的时候还绑定着事件处理程序呢。所以可以设置btn.onclick来移除事件处理程序。当然还有一种方法就是利用事件委托,把事件绑定在更高层次的元素上。
应用
1.当点击按钮开头添加时在<li>这里是</li>元素前添加一个新元素,内容为用户输入的非空字符串;当点击结尾添加时在最后一个 li 元素后添加用户输入的非空字符串.
当点击每一个元素li时控制台展示该元素的文本内容。
<ul class="ct">
<li>这里是</li>
<li>饥人谷</li>
<li>任务班</li>
</ul>
<input class="ipt-add-content" placeholder="添加内容"/>
<button id="btn-add-start">开头添加</button>
<button id="btn-add-end">结尾添加</button>
<script>
var btn1=document.querySelector('#btn-add-start')
var btn2=document.querySelector('#btn-add-end')
var ct=document.querySelector('.ct')
var ipt=document.querySelector('.ipt-add-content')
btn1.addEventListener('click',function(){
var Li=document.createElement('li')
if(ipt.value){
Li.innerText=ipt.value
ct.insertBefore(Li,ct.firstChild)
}
})
btn2.addEventListener('click',function(){
var Li=document.createElement('li')
if(ipt.value){
Li.innerText=ipt.value
ct.appendChild(Li)
}
})
ct.addEventListener('click',function(e){
console.log(e.target.innerText)
})
</script>
- 补全代码,要求:当鼠标放置在li元素上,会在img-preview里展示当前li元素的data-img对应的图片。
<ul class="ct">
<li data-img="1.png">鼠标放置查看图片1</li>
<li data-img="2.png">鼠标放置查看图片2</li>
<li data-img="3.png">鼠标放置查看图片3</li>
</ul>
<div class="img-preview"></div>
<script>
var ct=document.querySelector('.ct')
var img=document.querySelector('.img-preview')
ct.addEventListener('mouseover',function(e){
var imagelink=e.target.getAttribute('data-img');
var image=document.createElement('img');
image.setAttribute('src','imagelink');
img.appendChild(image);
});
</script>