HTML5事件

  通常产品都有一套用于人机交互的输入系统,都与电脑而言,大家最为熟知的鼠标、键盘,当然你也可以外接游戏手柄、3D左手鼠标等硬件输入设备,随着时间的推移 浏览器也开始支持VR设备,未来的浏览器不再仅仅是传统的网页载体,将会有众多的领域搬上网页。因此本节课就以鼠标和键盘为例,来展示外部输入设备,是如何于浏览器交互的。

鼠标事件

  下面的代码案例在《Javascript操作元素》中讲解过,可以回顾下,虽然都是同一个代码, 不同的知识量不同的情景你看到的想到的会有所不同,这里就不在展开讲解,更多类型的鼠标键盘事件可以查询 HTML事件属性

  鼠标键盘事件你可以理解为元素对象的属性,这么叙述其实暗含了添加鼠标事件的语法,比如单击鼠标事件onclick既然是元素属性,说明给元素添加鼠标事件和添加id等属性格式一样, onclick是对象的属性,那就是说给属性赋值的语法结构是“对象名.onclick = ”。

HTML标签中添加鼠标事件

<body>
<!--元素鼠标事件属性指向函数fun()-->
<div class="div" id="div" onclick="fun()"></div>
<script>
    //    等待鼠标调用函数fun()
    function fun() {
        let obj = document.getElementById("div");
        obj.style.backgroundColor="blue";
    }
</script>
</body>

Javascript添加鼠标事件

<body>
<!--需要添加鼠标事件的元素-->
<div class="div" id="div"></div>
<script>
    let obj = document.getElementById("div");
    function fun() {
        obj.style.backgroundColor="blue";
    }
    //给div元素添加鼠标事件
    obj.onclick = fun;
</script>
</body>

匿名函数添加鼠标事件

<script>
    let obj = document.getElementById("div");
    //    匿名函数添加鼠标事件
    obj.onclick = function () {
        obj.style.backgroundColor="blue";
    };
</script>

不同约束对象

  鼠标事件属性onclick、onmousemove、onmouseover等关键词的作用就是把函数和元素对象建立联系,也就是说你用鼠标单击一个元素,会触发与之相关的函数,并不是说你随意单击,就会触发一个函数执行。 大家都知道一个元素对象一般在网页上会有一定尺寸,占据一片区域,浏览器会实时监控鼠标的位置,当鼠标移动到一个元素区域的时候,这时候发生的事件就是onmousemove,不过如果你没有使用onmousemove关联 函数,那什么也不会发生,只是浏览器知道鼠标移动到了一个元素的上面。只要你的鼠标在网页上内容区域,那就一直在发生鼠标onmousemove事件。

//    给div元素添加鼠标事件
    obj.onclick = fun;
//    给body元素对象添加鼠标事件
    document.body.onclick =fun;
//    给document对象添加鼠标事件
    document.onclick = fun;
//    给window对象添加鼠标事件
    window.onclick =fun;

  阅读上的代码你可以看出,前两句代码都是给具体的HTML元素添加鼠标事件,第2句语句就是给页面显示区域元素的最顶层父元素body添加鼠标事件,这里注意,一般body里面的内容自上而下排列,如果内容较少,下面左右body子元素的下方单击页面空白处,是不会触发 body关联的事件,这一点好理解,父元素如果没有强制设置宽高度尺寸,那么它的块高度根据浏览器默认设置子元素自适应撑起来的,一般默认宽度是100%,高度由子元素排列占用高度决定。

  后两句代码不是给具体的HTML对象添加鼠标事件,document对象包含所有HTML元素对象,document对象又是window对象的子对象,通过window.document.getElementById()这种方式调用document对象的方法,window是浏览器顶级对象, 一些情况下编写代码的时候,可以省略不写。

比较鼠标事件

  HTML元素对象、document对象、window对象的鼠标键盘事件属性,又称为事件句柄。

属性 代表的事件
ondblclick 左键双击
onclick 左键单击
onmouseup 鼠标键松开
onmousedown 鼠标键按下
oncontextmenu 右键单击,默认菜单栏

  平时生活中不严谨的说法,单击网页的某个位置,往往指的就是单击左键。大家可以深入去思考,浏览器是如何判定单击事件的,可以去测试前面讲过的单击div颜色变化的案例,你可以先按下鼠标左键, 不松开,可以看到div背景颜色没有变化,松开左键后,颜色发生变化。说明左键单击onclick的判断依据是先发生左键被按下事件onmousedown,再发生左键松开事件onmouseup。 通过这样分解阐述你可以更好的理解按键按下、松开是怎么回事。鼠标左键双击ondblclick拆解来看就是两次鼠标按下,两次松开事件,但中间有个时间判定,如果两次单击间隔的时间过长,系统就会判定为两次单击事件, 而不是双击事件ondblclick,这样说比较感性,不具体,那么时间过长的定量标准是什么,间隔多少ms算时间过长。如果你只是做一个普通的单页不用深入研究, 如果你因为行业需要深入了解,可以结合数字电路和操作系统相关的中断事件、时间轮询等概念深入学习。

  onmouseup、onmousedown表示的松开、按下并不是仅仅针对左键,鼠标的右键、中键按下或松开同样会触发事件,至于鼠标被按下的是哪个键会通过左中右键被按下对应的0、1、2返回值去判断, 下面的课程会讲解,这里不展开叙述。

  不论键盘还是鼠标的按键按下或松开都会发生电位的变化,不论是有操作系统的计算机还是裸奔的单片机它都会做到实时检测按键的变化,按键开关的变化都会被程序记录下来,可以定位出备操作的是哪个鼠标键, 哪个键盘按钮,是按下了还是松开了。计算机判断键盘是否被操作的实时性是相对人而言,一般按下键盘需要几十毫秒或几百毫秒,在这个时间内,CPU的运行速度和操作系统分配的轮询时间完全不会漏掉忽视人的操作。

获取鼠标位置

源码下载

  下面代码的作用就是当鼠标在元素div上移动,也就是发生onmousemove事件,获取鼠标坐标位置然后显示在两个input标签创建的文本框里面。

6    <body>
7    <!--需要添加鼠标事件的元素-->
8    <div id="div" style="background-color: red;width: 500px;height: 300px"></div>
9    <!--显示鼠标纵横坐标的两个文本框x、y-->
10   <input type="text" value="" id="x">
11   <input type="text" value="" id="y">
12   <script>
13       let obj = document.getElementById("div");
14   //    获取文本框x
15       let X = document.getElementById("x");
16   //    获取文本框y
17       let Y = document.getElementById("y");
18       function fun() {
19   //        鼠标纵横坐标分别赋值给两个文本框的value属性
20           X.value =  event.clientX;
21           Y.value =  event.clientY;
22       }
23       //给div元素添加鼠标事件
24       obj.onmousemove = fun;
25   </script>
26   </body>

代码解析

  代码第8到第11行创建了一个div元素,和两个input文本框,给div元素添加一个鼠标被移动事件onmousemove,只要鼠标在div元素上移动,就会触发执行关联的函数fun(), 然后把div元素返回的鼠标坐标显示在input元素的value属性显示文本框里面,并且随着鼠标的移动数据实时更新。

属性 代表的事件
onmousemove 鼠标在被定义的对象上移动触发事件
onmouseenter 鼠标从其位置移动到被定义对象所在的位置触发事件

  注意区分事件句柄onmousemove和onmouseenter不同的地方,从书写的角度去看只差一个字母r,但是他们表达意义不一样,obj.onmousemove = fun;表示只要你的鼠标在obj对象上不停地移动,事件fun就不停的触发, obj.onmousemove = fun;表示放你的鼠标移动到obj对象上时,执行一次fun函数,如果你没有离开obj对象,鼠标再移动也不会触发fun函数。

  代码第18到第22行定义了一个函数,第20行代码X.value = event.clientX;的意思是把鼠标鼠标在浏览器页面(客户区)的横坐标event.clientX赋值给ipnut元素属性value。 鼠标触发相关元素的事件函数后会返回鼠标位置等信息,这些信息都会成为event对象的属性,按照W3C的标准event对象又属于window对象,完整的写法是window.event.clientX, clientY表示鼠标的纵坐标值,与client相对的是screenX、screenY他们的值分别代表鼠标在显示器屏幕上的坐标值。clientX、clientY的参考坐标原点是浏览器页面(客户区)的左上角, 也就是你打开空的html文件浏览器页面白色内容区域的左上角,你可以把body元素的内外边距设置为0,然后把鼠标滑动到div元素的左上角可以在input元素中返回(0,0),screenX、screenY 和clientX、clientY原点也是左上角,只不是是显示器的左上角不是浏览器页面。两个平面坐标系的正方向是一致的,x坐标水平向右,y坐标竖直向下。

  window的属性event,或者说clientX、clientY的对象event更多相关的属性,可以参考DOM Event对象

event坐标属性

属性 含义
clientX 鼠标横坐标(浏览器窗口客户区)
clientY 鼠标纵坐标(浏览器窗口客户区)
screenX 鼠标横坐标(屏幕)
screenY 鼠标纵坐标(屏幕)
鼠标坐标位置

鼠标按键返回值

源码下载

  本节课讲解event对象的button属性,clientX、clientY返回的值是鼠标的位置,button属性返回的值表示鼠标哪个按键被按下,左中右键对应的分别是0、1、2。

  如果你用过一些大型的设计软件,你应该体验过鼠标的一些按键组合起来实现一个平移、缩放或旋转的效果,不同的应用软件可能也略有差异。现在也有许多基于Web的应用,比如WebGL中的三维场景就需要用到鼠标的特殊操作, 普通的内容网页往往操作简单,比如很少出现鼠标中键和鼠标左键同时使用的现象,如果你暂时用不到,也不用深入学习,有个印象即可。

button值 对应鼠标键
0 左键
1 中键
2 右键

  下面代码完成的效果是如果左键按下元素显示红色,如果是中间右键分别对应绿色蓝色。

16   <div class="div" id="div"></div>
17   <script>
18       let obj = document.getElementById("div");
19       function fun() {
20           if(event.button == 0){//按下左键
21               obj.style.backgroundColor="red";
22           }
23           if(event.button == 1){//按下中键
24               obj.style.backgroundColor="green";
25           }
26           if(event.button == 2){//按下右键
27               obj.style.backgroundColor="blue";
28           }
29       }
30       obj.onmousedown= fun;
31   </script>
32   </body>

代码解析

  第30行代码 obj.onmousedown= fun;定义了一个按键按下的事件onmousedown,意味着当鼠标任何一个按键只要按下就会触发执行fun函数,同时浏览器会返回一个event对象,假设你按下的是鼠标中键,那么返回的event的属性button=1; fun函数执行的时候,第23行代码 if(event.button == 1)判断通过,执行打括号里面的语句obj.style.backgroundColor="green";,元素颜色变化绿色,你可以随意切换按下鼠标不同的左中右键,查看颜色的变化是否和代码设置一致。

鼠标滚轮缩放对象

测试滚轮事件返回值

源码下载

  为了实现通过鼠标的滚动轮缩放一个对象需要使用事件句柄onmousewheel添加鼠标滚轮事件,同时利用event对象的属性wheelDelta的属性值判断滚动的正反方向,wheelDelta的值不同的浏览器略有不同, 通过下面的代码可以测试浏览器wheelDelta的返回值是多少。很多时候浏览器关于同一个功能的实现方式可能不一样,导致不兼容,测试下面代码的时候,大家可以多尝试几个浏览器,不如火狐浏览器就不支持wheelDelta。

8    <body>
9    <div id="div" style="width: 500px;height: 500px;background-color: blue"></div>
10   <input type="text" value="" id="x">
11   <script>
12       let obj = document.getElementById("div");
13       let X = document.getElementById("x");
14       function fun() {
15           //获得鼠标滚动返回值wheelDelta
16           X.value =  event.wheelDelta;
17       }
18       //添加鼠标滚动事件
19       obj.onmousewheel= fun;
20   </script>
21   </body>
浏览器 谷歌chorme UC IE
向上滚动 +150 +120 +120
向下滚动 -150 -120 -120

缩放div元素代码

源码下载

  下面代码的作用就是当你把鼠标移动到div元素上面,上下滚动鼠标中键,可以实现div元素的缩放变化。如果你把鼠标移出div元素区域,在滚动鼠标滚轮可以发现,网页会上下滚动,这也说明鼠标滚轮默认的功能是通过滚动阅览网页, 不过一些设计软件中会使用鼠标滚轮缩放几何图形,所以有必要通过div元素的缩放来讲解滚轮缩放的功能实现,下面的代码只是一个教学展示,可能不能兼容所有的浏览器,但是对于初学者学习是没问题的。

6    <body>
7    <div id="div" style="width: 500px;height: 500px;background-color: blue"></div>
8    <script>
9        let obj = document.getElementById("div");
10       let w = 500,h = 500;//声明两个变量大小等于div的初始宽高度
11       function fun() {
12           if (event.wheelDelta > 0){//判断滚轮是否向上滚动
13               w += 10;
14               h += 10;
15           }
16           else if (event.wheelDelta < -0){//判断滚轮是否向下滚动
17               w -= 10;
18               h -= 10;
19           }
20           //变化后的宽高度值w、d赋值给width、height
21           obj.style.width=w+"px";
22           obj.style.height=h+"px";
23       }
24       //添加鼠标滚轮事件
25       obj.onmousewheel= fun;
26   </script>
27   </body>

代码解析

  第12行代码event.wheelDelta > 0是为了判断滚轮的滚动方向,不论是+150,还是+120,他们都大于0,这样写对于两种浏览器可以兼容,与之对应的是第16行代码event.wheelDelta < -0判断是否是另一个滚动方向。 执行两个判断语句后,会根据滚轮滚动方向,去增加或减小div宽高度

  第21行代码 obj.style.width=w+"px";是一个赋值语句,width属性赋值是一个字符串,比如常见的"100px",因为w是一个整数数字变量,不能写"wpx",这样的话Javascript解释器会识别为w、p、x三个字母组成的字符串, 如果写w+"px",浏览器的Javascript解释器会把隐式把w整数转化为字符串,就相当于写"w"+"px"。

键盘事件

  键盘事件和鼠标事件基本类似,小的区别是键盘事件的事件句柄较少只有三个,而键盘按键事件返回值keyCode比较多,有多少按键就有多少个返回值,具体返回值不用记忆可以查询《keyCode》。 大的区别方面键盘事件不是所有的HTML元素都支持,主要是你一般不会使用键盘去实现鼠标的单击、双击等事件,往往都是利用返回值,对于form表单元素一般都支持键盘事件,前提是该元素处于选中状态。

键盘事件:事件句柄

事件句柄 代表事件
onkeydown 键盘按下,类比onmousedown
onkeyup 键盘松开,类比onmouseup
onkeypress 单击按钮,类比onclick

keyCode

  keyCode和button都是event对象的属性,button属性的属性值是鼠标左中右键对应的返回值,keyCode属性的属性值是键盘上众多按键对应的返回值。

键盘事件案例一

源码下载

  创建一个文本框input,当输入文字的时候,按下按键文本框背景颜色变为红色,松开按键文本框背景颜色变为蓝色,当你输入文字的时候会看到颜色交替变换。

6    <body>
7    <!--创建文本框-->
8    <input type="text" value="" id="x">
9    <script>
10       let X = document.getElementById("x");
11       function down() {
12           //键盘按下文本框背景变红色
13           X.style.backgroundColor =  "red";
14       }
15       function up() {
16           //键盘松开文本框背景变蓝色
17           X.style.backgroundColor =  "blue";
18       }
19       //键盘按下事件
20       X.onkeydown= down;
21       //键盘松开事件
22       X.onkeyup= up;
23   </script>
24   </body>

键盘事件案例二

  上面的案例和鼠标的很多案例类似,给一个HTML元素添加键盘事件函数,下面利用event的属性keyCode来判断被按下的具体键盘。

  当键盘按键“k”被按下,用window的方法alert()弹出字母k。

<script>
    function fun() {
        if(event.keyCode == 75){//判断是否是键盘“k”键对应的keyCode值
            alert("k")
        }
    }
    window.onkeydown = fun;
</script>

鼠标键盘组合事件

  使用过电脑的普通用户至少都用过鼠标的快捷键,比如“Ctrl+S”,使用过与图形相关的平面设计、机械、建筑等行业的应用软件,往往会把键盘和鼠标同时使用快速操作几何图形。

  常用的几何常常用来图其他软件组合的Ctrl、shift、alt键都有相关的event属性来判断,比如ctrlKey,当你按其它按键之前按下Ctrl保持不松开,再去按其它按键,event.ctrlKey返回的结果是true,否则是false。

event属性 含义
ctrlKey true/false 发生键盘事件时,Ctrl键是否是被按下状态
shiftKey true/false 发生键盘事件时,Shift键是否是被按下状态
altKey true/false 发生键盘事件时,Alt键是否是被按下状态

键盘按键组合实例

<script>
    //模拟平时常见的操作Ctrl、shift等快捷键操作
    function fun() {
        //判断按回车键的时候是否按Ctrl键
        if(event.keyCode == 13 && event.ctrlKey){
            alert("Ctrl+回车")
        }
        //shift+Z
        if(event.keyCode == 90 && event.shiftKey){
            alert("shift+Z")
        }
        //Ctrl+shift+Z
        if(event.keyCode == 90 && event.ctrlKey && event.shiftKey){
            alert("Ctrl+shift+Z")
        }
        //避免“Ctrl+shift+Z”触发"shift+Z",event.ctrlKey执行非操作
        if(event.keyCode == 90 && (!event.ctrlKey) && event.shiftKey){
            alert("shift+Z")
        }
    }
    window.onkeydown = fun;
</script>

键盘鼠标组合实例

<script>
    //鼠标和键盘组合
    function fun() {
        //鼠标左键和键盘Ctrl键
        if(event.button == 0 && event.ctrlKey){
            alert("Ctrl+左键")
        }
    }
    window.onmousedown = fun;
</script>

addEventListener()

  addEventListener()是HTML元素element对象、wondow对象具有的方法,通过该方法可以给一个对象指定当鼠标键盘等事件发生后要执行的函数,相比前面直接给事件属性添加函数名字作为属性值,绑定事件函数的方式, 可以自定义更多的内容,在深入学习之前先来展示一个,简单的鼠标单击事件调用的方法。

直接给对象的事件属性赋值

<body>
<!--给div元素注册鼠标事件-->
<div id="div" style="width: 50px;height: 30px;background-color: blue"></div>
<script>
    let obj = document.getElementById("div");
    function fun() {
        //单击div蓝色变红色
        obj.style.backgroundColor="red";
    }
    //事件属性赋值法
    obj.onclick = fun;
</script>
</body>

调用对象的addEventListener()方法

<body>
<!--给div元素注册鼠标事件-->
<div id="div" style="width: 50px;height: 30px;background-color: blue"></div>
<script>
    let obj = document.getElementById("div");
    function fun() {
        //单击div蓝色变红色
        obj.style.backgroundColor="red";
    }
    //事件属性和函数名字作为addEventListener参数法
    obj.addEventListener("click",fun)
</script>
</body>

  obj.addEventListener("click",fun)就表示给obj对象绑定函数fun,触发方式是click,也就是前面常说的鼠标单击事件onclick,前面讲到的对象的事件属性名字作为addEventListener()方法参数的时候不需要使用开头的两个字母 on。第一个参数是事件名字的字符串形式,第二个参数是一个变量,也就是函数的名字。

事件流

结构树—事件流

  前面将结果HTML的元素会组成一个树结构,事件流就是指事件在元素树结构上传播的过程,从上到下(根节点到子节点)是捕获型事件,从下到上(子节点到根节点)是冒泡型事件,就像水泡一样从水底到水上,在编程中 常常用来形容算法。用人话说就是比如两个div元素是父子嵌套关系,假设两个元素都定义了鼠标单击事件,当你单击子元素div的时候,实际上是触发了两个div元素的鼠标事件,那么先执行谁,就是一个问题,如果先执行子元素, 这就类似水泡,从子元素向父元素开始逐层执行,从里向外执行,这就是冒泡型事件,执行顺序反过来就是捕获型事件。

  addEventListener("事件名",函数名,Boolean)方法的第三个参数是布尔值,如果Boolean是true,表示方法定义的事件是捕获型事件,false代表冒泡型事件,通过布尔值来定义执行顺序,addEventListener第三个参数默认是 false。