JavaScript 事件分类
一、鼠标事件
click、mousedown、mousemove、mouseup、contextmenu、mouseover、mouseout、mouseenter、mouseleave
用e.button来区分鼠标的按键,0/1/2
DOM3标准规定: click事件只能监听左键, 只能通过mousedown 和 mouseup来判断鼠标键
如何解决mousedown和click的冲突
1、click是敲击鼠标事件
click = mousedown + mouseup 是一个过程,
看一下click、mousedown、mouseup这三个事件的触发顺序
document.onclick = function(){
console.log('click');
}
document.onmousedown = function(){
console.log('mousedown');
}
document.onmouseup = function(){
console.log('mouseup');
}
// mousedown、mouseup这两个是一组顺序是先mousedown,后mouseup,再click,跟绑定顺序没关系

2、其他鼠标事件
contextmenu 右键弹出菜单事件,它唯一有用处的地方就是右键取消菜单,它监听右键不好吗,监听右键另外有方法不用这种麻烦的方法
mousemove 鼠标移动的事件
mouseover 鼠标挪入
mouseout 鼠标挪出
mouseenter 鼠标挪入(HTML5新规范)
mouseleave 鼠标挪出(HTML5新规范)
3、鼠标挪入\鼠标挪出
mouseover事件 鼠标移入的时候发生
mouseout事件 鼠标离开的时候发生
<div style="width:100px;height:100px;background-color:yellow;"></div>
<script>
var div = document.getElementsByTagName('div')[0];
div.onmouseover = function(){
div.style.backgroundColor = "tomato";
}
div.onmouseout = function(){
div.style.backgroundColor = "yellow";
}
</script>HTML5新的规范是mouseenter、mouseleave,css的内部原理hover就是用js写的
<div style="width:100px;height:100px;background-color:yellow;"></div>
<script>
var div = document.getElementsByTagName('div')[0];
div.onmouseenter = function(){
div.style.backgroundColor = "tomato";
}
div.onmouseleave = function(){
div.style.backgroundColor = "yellow";
}
</script>4、总结
click 鼠标点击
mousedown 鼠标点击按下
mouseup 鼠标抬起
mousemove 鼠标移动
contextmenu 鼠标左键
mouseover 鼠标移入(老版本)
mouseout 鼠标移出(老版本)
mouseenter 鼠标移入(HTML5新版本)
mouseleave 鼠标一出(HTML5新版本)
5、用事件对象里的button属性来区分鼠标的按键
有些需求就想左键出来什么东西、右键出来什么东西,
比如扫雷游戏左键打开、右键插旗,必须知道什么时候左键、什么时候右键
如何区分鼠标的左右按键?
能区分左右键的只有两个事件,一个是mouseup一个是mousedow,其它的事件都不可能
先试一下 onmousedown 左键点击按下
document.onmousedown = function(e){
console.log(e);
}左键点击一下,
1). 控制台出来事件对象,事件对象上有一个button属性,
2). 这个button属性记载了鼠标是右键的还是左键,
3). 如果左建返回 0
如果右键返回 2
如果是中间滚动轮返回 1

右键点击botton是2

所以判断e.button的值就知道左键还是右键了
document.onmousedown = function(e){
if(e.button == 2){
console.log('右键点击');
}else if(e.button == 0){
console.log('左键点击');
}
}
mousedown和mouseup是一组的
1). mousedown 鼠标按下能判断左键右键
2). mouseup 鼠标抬起也能这样判断
6、click事件不能的监听左键的
click对右键的监听基本上是无能为力的状态,右键没触发click事件
document.onclick = function(e){
console.log(e);
}click点击右键,在控制台没有显示任何内容,只在页面弹出右键菜单

w3c规定click事件只能监听左键不能监听右键,能触发右键的只有mousedow和mouseup
7、如何解决mousedown和click的冲突
问一个问题,
拖拽一个小方块,这个小方块还是一个A标签,
A标签有个特性,在他上面写网址一点击就跳转页面了,
现在把A标签做成可以拖拽的方块
要求
拖拽的时候让方块A标签正常拖拽,
点击的时候方块A标签正常跳转
实现的关键点在哪?
拖拽是一个mousedown事件、一个mousemove事件、一个mouseup事件,
但一个mousedown、一个mouseup不管隔多长时间都算一个click事情,
就是拖拽不能跳转页面,怎么来区分拖拽和点击呢?
用户想拖拽的时候就拖,不执行点击事件,如果想执行点击的时候,不执行拖拽,简单的说就是拖拽不等于点击怎么办?
时间差的问题,
想一个问题,正常拖拽一个东西需要一点时长,不能点完之后蹭一下就起来了,没那么快至少要0.2秒以上才叫拖拽,
click点击没有那么慢,一般情况下点击是清脆的,点完一下之后基本0.2秒到0.3以内秒就抬起来了,所以可以用生物行为来区分是拖拽还是点击。
鼠标按下、抬起的时间差
1). 小于300毫秒(0.3秒)是点击
2). 大于300毫秒是拖拽
<div style="width:100px;height:100px;background-color:red;position:absolute;left:0;top:0"></div>
<script>
var div = document.getElementsByTagName('div')[0],
firstTime = 0,
lastTime = 0,
key = false;
div.onmousedown = function() {
firstTime = new Date().getTime(); // 1. onmousedown的时候记载一个时间戳
}
document.onmouseup = function(){
lastTime = new Date().getTime();
if(lastTime - firstTime < 300){ // 2. 小于300毫秒是点击
key = true; // 3. 小于300毫秒,开关打开key等于true
}
}
document.onclick = function(){
if(key){ // 4. 小于300是点击,让click点击执行了,里面有一个开关key
console.log('小于300毫秒是click点击事件');
key = false; // 5. 小于300进入判断,让key等于false
}
}
</script>普通点击鼠标,打印出小于300毫秒是click点击事件,按住鼠标左键不释放,再抬起来没有click事件,
这就区分开左右键了,然后把拖拽功能放到mousedown、mouseup里面。
mousedown触发了拖拽事件,mousedown事件之后在它里面写mousemove,也就是按下之后绑定mousemove事件,方块才跟着鼠标移动,鼠标抬起来之后把mousemove事件解除
<div style="width:100px;height:100px;background-color:red;position:absolute;left:0;top:0"></div>
<script>
var div = document.getElementsByTagName('div')[0],
disX,
disY,
firstTime = 0,
lastTime = 0,
key = false;
div.onmousedown = function(e) {
var e = e || window.event;
firstTime = new Date().getTime();
disX = e.pageX - parseInt(div.style.left);
disY = e.pageY - parseInt(div.style.top);
document.onmousemove = function(e){ // 按下之后绑定mousemove事件
var e = e || window.event;
div.style.top = e.clientY - disX + 'px';
div.style.left = e.clientX - disY + 'px';
}
}
document.onmouseup = function(){
lastTime = new Date().getTime();
if(lastTime - firstTime < 300){
key = true;
}
document.onmousemove = null; // 抬起来之后mousemove事件就解除
}
document.onclick = function(){
if(key){
console.log('小于300毫秒是点击');
key = false;
}
}
</script>8、事件练习作业
拖拽应用(已做)
应用 mousedown、mousemove、mouseup(已经做)
随机移动的方块
mouseover
随机移动的方块 :
一个方块在屏幕中间,当鼠标放到方块上面的时候就是mouseover事件的时候,方块随机向上、下、左、右、斜上、斜下,斜左、斜右八个方向随机挪动100像素的距离。
造成一个效果就是无论鼠标怎么往方块里面移都碰不到方块,鼠标移到方块上面方块就随机移动了,鼠标碰不到方块。
二、键盘事件
keydown、keyup、keypress
keydown > keypress > keyup
keydown和keypress的区别
keydown 可以响应任意键盘按键,keypress只可以相应字符类键盘按键
keypress返回ASCII码,可以转换成相应字符
还有几个移动端的事件目前比较超纲,移动端mousedown就不好使了,
移动端叫touch事件有三个touchstart、touchmove、touchend,
移动端的touchstart、touchmove、touchend和mousedown、mouseup是一样的。
1、keydown、keyup、keypress
键盘事件很关键,比如贪吃蛇游戏就需要键盘事件,键盘事件就三个keydown、keyup、keypress
依照鼠标的规律来看一个click相当于mousedown + mouseup,键盘这里大概是一个keypress等于keydown + keyup,猜一下是不是这样?
document.onkeypress = function(){
console.log('keypress');
}
document.onkeydown = function(){
console.log('keydown');
}
document.onkeyup = function(){
console.log('keyup');
}随便点一个按键a测一下,一个keypress不等于keydown + keyup

而且按住键盘不动,没有keyup反复出现keydown、keypress

然后键盘抬起keyup才出来

keypress跟keydown、keyup两个没关系
2、keydown > keypress > keyup
首先keydown和keyup是一对,触发顺序是先keydown后keypress再keyup,其实keydown和keypress差不多,但是有点小区别。
连续按的时候不抬起,就一直触发keydown和keypress这样有什么好处呢,为什么鼠标没连续触发,键盘连续触发呢?
比如CS游戏,"w、s、a、d"四个键,控制上、下、左、右四个方向跑,如果游戏设定按一下键盘,只能触发一下不连续触发,要想连续跑,手要点抽筋了,
所以游戏设计的很合理,按住之后连续触发,能保证触发事件的时候有一个连贯性,游戏也应用了这一点。
不仅是js,所有语言都有键盘事件一样的,也是按住连续一直触发。
问大家一个问题,假如让我们设计一个游戏,先不用管keydown和keypress的区别,有个游戏叫《英雄联盟》非常简单就几个键q、w、e、r、f,
有的人为了打游戏拼反应速度,买专门的机器键盘,机器键盘的好处是键盘里面是机器轴承,抬起的速度特别快,按键的回馈特别快,按下去非常难按,按完之后就弹起来了速度非常快,
如果我们设计游戏,把游戏的事件设置在keydown/keypress上还是keyup上?肯定是绑定在keydown上,按下技能就释放不用抬起来,普通键盘就能玩的很好,只要不影响按下去的速度就行。
3、keydown和keypress的区别
keydown、keypress它俩到底有什么用?
专门对比keydown、keypress,分别打印它们的事件对象e
document.onkeypress = function(e){
console.log(e);
}
document.onkeydown = function(e){
console.log(e);
}触发顺序是先触发keydown按下键盘a键

第一个事件对象是keydown,点开看里面的charCode属性值是0

keypress事件对象里面的charCode返回的是97,小写a的ACSII码就是97

第一区别是charCode属
keydown事件charCode属性 没有值
keypress事件harCode属性 有值
charCode属性有什么用呢?
再按方向键上,发现少了一个事件,再按下也少了个事件,少的是keydown还是keypress?

点开第一个keydown的事件对象,charCode属性值依然是0,事件类型是type: keydown

也就是说上、下、左、右这些方向键keypress没有触发,还有一些键Ctrl、CapsLock、Alt、Shift这些控制类的键都不触发keypress
解释一下keypress和keydown是干什么的?
1). keydown能够监测到所有的键盘类按键事件(除fn以外)
2). keypress只能监测到字符类按键
字符类按键什么意思?
ACSII码表里面找,ACSII表里面没有的都不叫字符按键,所以keypress按出来的会对应ACSII码
keydown能做这么多事,所有按键都能监听,那为什么不用keydown?
它有一个小问题,比如按一下小写的a键,keydown和keypress都出现了,keydown知道按键按的是什么吗?

点开keydown的事件对象,charCode的值是0,往下看which的值是65

按一下小写的b键,keydowan事件对象里 which: 66

有个which属性一个是65一个是66,这不能判断是a吗?判断不了
看好按"shift + a",也就是大写的A

"shift + a"的keydown事件对象,which属性的值结果也是 65

我们直接把which属性打印出来
document.onkeypress = function(e){
console.log('keypress:' + ' charCode: ' + e.charCode);
console.log('keypress:' + ' which: ' + e.which);
}
document.onkeydown = function(e){
console.log('keydown: ' + ' charCode: ' + e.charCode);
console.log('keydown: ' + ' which: ' + e.which);
console.log(' ');
}按一下小写的a键

keydown:charCode值是0,which的值还是65
keypress: cherCode值97,which的值是97
说明keydown检测字符类按键是不准的,大写A小写a都是which:65怎么检测,但字符类按键keypress监控的很准
这两个怎么配合呢?
如果想监控字符类按键并且区分大小写用keypress,如果操作类按键用只能用keydown,
操作类按键keydown也没什么不好,比如上、下、左、右对应的位置which属性都有值而且是唯一的。
document.onkeydown = function(e){
console.log(e.which);
}上 which:38
下 which:40
左 which:37
右 which:39

这个which属性到底是什么?
which不是ASCII码,他检测的是108个键的排位号,他的数字对应一个键,但对应不了shift+字母键(大写的字母),就看要求精准不精准。
如果键盘类事件不管大小写要求没那么高,只要检测到那个按下就行了,那keydown解决一切问题。
但是keydown解决的问题的不好,字母和数字这些键对应的位置不是按ACSII码表来的,要挨个对应挨个测,keypress直接是按照ACSII表直接能把键拿出来了看的更精准一些。
e.charCode是ACSII码,如何把ACSII码转换成字母?
String.fromCharCode() 方法直接往里面放uncoded编码,会把uncoded编码转换成对应的字符,uncoded编码是包含ASCII码的
document.onkeypress = function(e){
console.log(String.fromCharCode(e.charCode));
}a、b、c、d都有,而且shift + a、shift + b都行

大任务都完成了,接下来就是边边角角了
三、文本类操作事件
input事件
focus事件
blur事件
change事件
1、input事件
写一个input文本框
<input type="text" style="border:1px solid grey;outline:none;"/>
<script>
var inp = document.getElementsByTagName('input')[0]; // 获取input文本框
inp.oninput = function(){ // 获取完后设置一个"oninput"事件
console.log(this.value);
}
</script>写一个a打印出一个a,再写一个b打印出ab,输入一次就触发一次,然后删除一个b也触发了

但凡input框里面的文本有变化,都会触发input事件不论删还是新增
2、change事件
change事件的意思是,首先聚焦,发生改变,失去焦点,然后触发事件了
<input type="text" style="border:1px solid grey;outline:none;"/>
<script type="text/javascript">
var inp = document.getElementsByTagName('input')[0];
inp.onchange = function(){
console.log(this.value);
}
</script>change事件对比的是"鼠标聚焦"和"失去焦点"两个状态是否发生改变,如果两个状态没发生改变不触发事件,如果发生改变触发,
不管中间怎么操作,删了多次减了多少次,只要两个状态不一样就触发change,只要两个状态一样就不触发。
3、focus事件和blur事件
focus事件,鼠标聚焦
blur事件,鼠标失去焦点
模仿新浪写一个"请输入用户名"鼠标聚焦提示文字消失,鼠标失去焦点提示文字出来,用句柄方式写
首先下面代码是不完美的,但至少实现了点完后input框的提示文本没了,失去焦点提示文字"请输入用户名"又出来了
<input type="text" style="outline:none;" value="请输入用户名" onfocus="this.value=''" onblur="this.value='请输入用户名'" />
现在点击输入文字,失去焦点后刚刚输入的文字没了,又出现提示文字"请输入用户名",应该在什么情况下提示文字才回来或者在什么情况下提示文字失去?
在输入框为空的情况下,提示文字"请输入用户名"才回来
<input type="text" style="outline:none;"
value="请输入用户名"
onfocus="if(this.value=='请输入用户名'){this.value='';}"
onblur="if(this.value==''){this.value='请输入用户名';}"
/>改一下样式的颜色,互联网标准颜色#999,maxlength="40"最长字符不能超过40个
<input type="text"
style="outline:none; border:1px solid rgba(0,0,0, .3); color:#999;"
value="请输入用户名"
onfocus="if(this.value=='请输入用户名'){this.value=''; this.style.color='#424242';}"
onblur="if(this.value==''){this.value='请输入用户名'; this.style.color='#424242';}"
/>缺陷是写"请输入用户名"就没了
四、窗体操作类(window上的事件)
scroll 滚动条滚动时间
load
小练习: fixed定位 js兼容版
当滚动条一滚动,scroll事件就触发了,scroll是window上的事件
<div style="height:3000px; width: 3000px; background-color: khaki;"></div>
<script>
window.onscroll = function(){
console.log(window.pageXOffset + " " + window.pageYOffset); // 当滚动条滚动的时候获取滚动条滚动位置。
}
</script>还记得有一个position:fixed意思相对可视区窗口,但是有一个问题IE6没有fixed定位,如何用js给IE6写一个fixed定位,用position:absolute来模拟
position:absolute有个问题是文档往上一托就托上去了,如何保持它相对视口的位置不变呢?top等于原来的top加上滚动条的位置
把页面滚动的距离加到top上,就相当于这个方块没动
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>模拟fixed定位</title>
<style>
body{
height:3000px;
}
</style>
</head>
<body>
<div style="height:100px;width:100px;background-color:moccasin;position:absolute;top:30px;right: 30px;"></div>
<script>
var oBox = document.getElementsByTagName('div')[0];
window.onscroll = function(){
console.log(oBox.style.top);
oBox.style.top = 30 + window.pageYOffset + 'px';
}
</script>
</body>
</html>加定时器有点延迟的效果
var oBox = document.getElementsByTagName('div')[0];
window.onscroll = function(){
setInterval(function(){
oBox.style.top = 30 + window.pageYOffset + 'px';
}, 100);
}load很重要,重要不是去用,是让不去用,
读到js的时候就阻断页面,所以把js写到div元素下面,才能把上面的div元素读出来
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>load</title> </head> <body> <div></div> <script> </script> </body> </html>
如果把div元素写在js标签下面,肯定选不出来这个div,因为页面还没渲染到那,就卡死了执行js了,js是读到它执行完再往下读
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>load</title>
</head>
<body>
<script>
var div = document.getElementsByTagName('div')[0];
console.log(div); // undefined
</script>
<div></div>
</body>
</html>有些人这样写,可以选出div元素而且还能操作div
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>load</title>
</head>
<body>
<script>
window.onload = function(){
var div = document.getElementsByTagName('div')[0];
console.log(div); // <div></div>
div.style.height = '100px';
div.style.width = '100px';
div.style.backgroundColor = 'red';
}
</script>
<div></div>
</body>
</html>这个方法是最慢的没意义是最关键的一点
