Go to comments

JavaScript 事件分类

一、鼠标事件

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,跟绑定顺序没关系

image.png

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

image.png


右键点击botton是2

image.png


所以判断e.button的值就知道左键还是右键了

document.onmousedown = function(e){

    if(e.button == 2){
        console.log('右键点击');
    }else if(e.button == 0){
        console.log('左键点击');
    }

}

image.png


mousedown和mouseup是一组的

1). mousedown 鼠标按下能判断左键右键

2). mouseup 鼠标抬起也能这样判断

6、click事件不能的监听左键的

click对右键的监听基本上是无能为力的状态,右键没触发click事件

document.onclick = function(e){

    console.log(e);

}

click点击右键,在控制台没有显示任何内容,只在页面弹出右键菜单

image.png


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、事件练习作业


随机移动的方块 : 

一个方块在屏幕中间,当鼠标放到方块上面的时候就是mouseover事件的时候,方块随机向上、下、左、右、斜上、斜下,斜左、斜右八个方向随机挪动100像素的距离。

造成一个效果就是无论鼠标怎么往方块里面移都碰不到方块,鼠标移到方块上面方块就随机移动了,鼠标碰不到方块。


二、键盘事件


还有几个移动端的事件目前比较超纲,移动端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

image.png


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

image.png


然后键盘抬起keyup才出来

image.png

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键

image.png


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

image.png


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

image.png


第一区别是charCode属

keydown事件charCode属性  没有值

keypress事件harCode属性    有值


charCode属性有什么用呢?


再按方向键,发现少了一个事件,再按也少了个事件,少的是keydown还是keypress?

image.png


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

image.png


也就是说上、下、左、右这些方向键keypress没有触发,还有一些键Ctrl、CapsLock、Alt、Shift这些控制类的键都不触发keypress


解释一下keypress和keydown是干什么的?

1). keydown能够监测到所有的键盘类按键事件(除fn以外)

2). keypress只能监测到字符类按键


字符类按键什么意思?

ACSII码表里面找,ACSII表里面没有的都不叫字符按键,所以keypress按出来的会对应ACSII码


keydown能做这么多事,所有按键都能监听,那为什么不用keydown?

它有一个小问题,比如按一下小写的a键,keydown和keypress都出现了,keydown知道按键按的是什么吗?

image.png


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

image.png


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

image.png

有个which属性一个是65一个是66,这不能判断是a吗?判断不了


看好按"shift + a",也就是大写的A

image.png


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

image.png


我们直接把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键

image.png

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

image.png


这个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都行

image.png

大任务都完成了,接下来就是边边角角了

三、文本类操作事件

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也触发了

image.png

但凡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事件就触发了,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>

这个方法是最慢的没意义是最关键的一点



Leave a comment 0 Comments.

Leave a Reply

换一张