Open AlexZ33 opened 4 years ago
要了解事件处理,首先需要知道的一个概念就是“事件”。“事件”本身是一个抽象的概念,也是一个对象, 它是表现另外的对象状态变化的对象。日常生活中,“事件”随处可见。例如,按下电脑的电源键电脑就开机了。在这里“按下电脑的电源键”就是一个事件,这个事件的结果就是“电脑开机了”,看到的就是电脑处理“按下电源键”这个事件的结果,而这个处理的过程就是本书要说的事件处理。事件处理是面向对象编程的一个重要概念,而JavaScript是一种基于对象 与事件驱动的脚本语言,因此,事件处理在JavaScript中也是一个重要概念。简单地说,“事件处理” 就是当对象的状态改变时( 电脑的电源键由正常改变为被按下),对象应对这种改变的动作(电脑对电源键状态的改变进行的处理过程)。对事件进行处理的程序或函数称为“事件处理”。在JavaScript中,鼠标、键盘、文档的状态改变(动作)称为事件;由鼠标、键盘、文档引发的一系列的程序动作, 称为事件驱动;对发生的事件进行相应处理的程序或函数,称为事件处理函数。JavaScript 的事件处理函数使用function函数的形式定义,方法如下:
function funcName(params,...) { Do something...//事件处理的脚本 }
其中,funcName 是事件处理函数的函数名,这是必需的(某些情况下用户可以定义匿名的事件处理函数,window.onload-function()...})。事件处理函数可以有()至多个参数,用户可以根据需要指定。指定某个事件的事件处理函数的方法是:事件=事件处理函数名()。例如,在如下所示的代码中,“ 单击”按钮的onclick事件有一个名为clkHandle的事件处理函数。
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <title>JavaScript基础 - 04 - DOM事件</title> <meta name="description" content="图灵斯顿俱乐部--IT前端中级课程, JavaScript基础 - 04 - DOM事件, 报名微信:hututu52533" /> <meta name="viewport" content="width=device-width, initial-scale=1"> </head> <body> <p> 事件处理演示:<input type="button" value="单击" onclick="clkHandle()" /> </p> <script> function clkHandle() { //单击按钮 onclick 事件处理函数 window.alert("点击“单击”按钮的onclick事件处理函数"); } </script> </body> </html>
在上述代码中,指定了“单击”按钮的onclick事件及其名为ckHande()的事件处理函数。在JavaScript中,指定某个事件的事件处理函数的方法,就是给某个HTML元素的事件名属性赋值为函数的函数名。上述代码运行时,单击页面中的“单击”按钮,会弹出如下图所示的提示信息。在JavaScript中,事件类型分为很多中,如鼠标事件、键盘事件、HTML事件、变动事件。本课程将对这些事件一一叙述、娓娓道来。
鼠标事件是指鼠标状态的改变,包括鼠标在移动过程中、单击过程中、拖动过程中等有鼠标状态改变触发的事件。常用的鼠标事件有onclick单击事件、ondblClick 双击事件、onmouseout鼠标离开事件、onmouseover鼠标移到上方事件、onmouseup鼠标放开事件、onmousedown鼠标按下事件和onselect选中事件等。
onclick 事件在鼠标单击某元素时触发。单击是指鼠标停留在对象上,按下鼠标按键,没有移动鼠标而放开鼠标按键这一个完整的过程。我们在以后的开发过程中,最常用也是最常碰到的事件处理就是onclick鼠标单击事件,从之前的课程中学员们应该有所体会。
document.getElementById("btn").onclick = function() { document.getElementById("welcome").innerHTML = 'Hello ' + document.getElementById("name").value; }
ondblClick事件在鼠标双击某元素时触发。双击事件是在较短的时间内,连续两次完成鼠标单击事件。例如,要求双击ul-->li 中的某一行时, 此行显示与其他行不同的背景色(整个页面的色是白色),具体实现方法如代码所示:
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <title>JavaScript基础 - 04 - DOM事件</title> <meta name="description" content="图灵斯顿俱乐部--IT前端中级课程, JavaScript基础 - 04 - DOM事件, 报名微信:hututu52533" /> <meta name="viewport" content="width=device-width, initial-scale=1"> <style> .ul-color { display: flex; flex-direction: column; width: 120px; } .ul-color .ul-li { cursor: pointer; border-bottom: solid 1px #d1d1d1; line-height: 32px; } </style> </head> <body> <p> ondblClick 双击事件: <ul class="ul-color"> <li class="ul-li" ondblclick="changeColor(this, 'red', 'white')">无中生有</li> <li class="ul-li">暗渡成仓</li> <li class="ul-li">凭空想象</li> <li class="ul-li">凭空捏造</li> </ul> </p> <script> function changeColor(ele, color, fontColor) { //单击按钮 ondblClick 事件处理函数 ele.style.background = color; ele.style.color = fontColor } </script> </body> </html>
在适当的地方正确使用鼠标双击事件可以提高页面的显示效果,改善用户体验。
onmousovser事件在鼠标进入对象范围(移到对象上方)时触发。文本框所在元素li的HTML,代码如下:
<p style="text-indent: 20px;" onmouseover="mouseover(this)" >鼠标还没有来过。</p>
当鼠标进入单元格时,触发onmouseover事件,调用名称为modStyle的事件处理函数,完成对单元格样式的更改。onmouseover 事件可以应用在所有的HTML页面元素中,例如,鼠标经过文字上方时,显示效果为“鼠标来到了我的上面^_^”,鼠标离开后,显示效果为“鼠标从我上面离开了T。T”。其实现方法如下:
function mouseover(ele) { //鼠标移入事件 onmouseover ele.innerText = "鼠标来到了我的上面^_^"; }
onmouseout事件在鼠标离开对象时触发。onmouseover事件通常与onmouseover事件共同使用改变对象的状态。
<p style="text-indent: 20px;" onmouseover="mouseover(this)" onmouseout="mouseout(this)">鼠标还没有来过。</p>
function mouseover(ele) { //鼠标移入事件 onmouseover ele.innerText = "鼠标来到了我的上面^_^"; } function mouseout(ele) { //鼠标离开事件 ele.innerText = "鼠标从我上面离开了T。T"; }
onmousedown事件在用户把鼠标放在元素上按下鼠标是触发。下面我们来看下下面这个演示demo:
<p id="mousedown" onmousedown="mousedown(this)"></p>
function mousedown(ele) { //鼠标按下事件 onmousedown let xPst = event.clientX; //获得X坐标 let yPst = event.clientY; //获得Y坐标 ele.innerText = `X坐标为:::::${xPst} \n Y坐标为:::::${yPst}`; ele.style.cursor = "hand"; ele.style.background = "red"; ele.style.color = "white"; ele.style.border = "5px solid blue"; }
onmouseup事件在用户把鼠标放在对象上鼠标按键被按下的情况下,放开鼠标键时触发。如果接收鼠标键按下事件的对象与鼠标键放开时的对象不是同一个对象,那么onmouseup事件不会触发。onmousedown 事件与onmouseup事件有先后顺序,在同一个对象上前者在先后者在后。onmouseup事件通常与onmousedown事件共同使用控制同一对象的状态改变。我们继续刚刚的代码示例,添加onmouseup事件进入:
<p id="mousedown" onmousedown="mousedown(this)" onmouseup="mouseup(this)"></p>
function mousedown(ele) { //鼠标按下事件 onmousedown let xPst = event.clientX; //获得X坐标 let yPst = event.clientY; //获得Y坐标 ele.innerText = `X坐标为:::::${xPst} \n Y坐标为:::::${yPst}`; ele.style.background = "red"; ele.style.color = "white"; ele.style.border = "5px solid blue"; } function mouseup(ele) { ele.innerText = "鼠标松开了"; let eleStyle = ele.style; eleStyle.background = "#d1d1d1"; eleStyle.color = "#000"; eleStyle.border = "none"; }
onselect事件在文本框或是文本域的内容被选中时(选中的部分高亮显示)触发。onselect事件的具体过程是从鼠标按键被按下,到鼠标开始移动并选中内容的过程。这个过程并不包括鼠标键的放开。例如在一一个 HTML页面中,当用户选择文本框中的文字时,在div中显示用户选中的文字内容。其实现方法如下:
<p> onselect 选中事件 <p> <input style="width: 200px;" type="text" placeholder="请输入内容让后选中试试看吧" onselect="selectDemo(this)" /> </p> <p> <textarea style="width: 200px;" onselect="selectDemo(this)"></textarea> </p> <div id="showSelectValue"> 还没有选中内容哦,快选中内容试试看吧 </div> </p>
function selectDemo(ele) { let choseStr = window.getSelection(); //获得当前选中文本 document.getElementById("showSelectValue").innerText = choseStr; }
[MDN] selection 详解
键盘事件是指键盘状态的改变,常用的键盘事件有onkeydown 按键事件、onkeypress 按下键事件和onkeyup放开键事件等。
onkeydown事件在键盘的按键被按下时触发。onkeydown事件用于接收键盘的所有按键(包括功能键)被按下时的事件。onkeydown 事件与onkeypress事件都在按键按下时触发,但是两者有区别,详情下面onkeypress和onkeyup的讲解。例如,在用户输入信息的界面中,为方便用户使用,通常情况下,当用户按回车键时,触发页面登陆、提交等等功能。
<input value="敲下回车试试看吧" type="text" name="keydown" onkeydown="if(event.keyCode==13) alert('同学们好!!!');" />
onkeypress事件在键盘的按键被按下时触发。onkeypress事件与onkeydown事件两者有先后顺序,onkeypress事件是在onkeydown事件之后发生的。此外,当按下键盘上的任何一个键时,都会触发onkeydown事件;但是onkeypres事件只在按下键盘上的任字符键(如A~Z、数字键)时触发,但是单独按下功能键(F1~F12)、Ctrl键、Shift键、Alt键等,不会触发onkeypress事件。onkeydown事件与onkeypress事件执行的先后顺序,其代码如下:
function keydwnHandle() { alert("onkeydown 事件触发") } function keyprsHandle() { alert("onkeypress 事件触发") }
onkeyup事件在键盘的按键被按下然后放开时触发。例如,页面中要求用户输入内容后,使用onkeyup事件,获取文本框中输入内容的长度,示例如下:
<p> onkeyup 放开键事件 <input type="text" name="keyup" onkeyup="keyupHandle(this);" /> <span id="keyupNum"></span> </p>
function keyupHandle(ele) { document.getElementById("keyupNum").innerText = "输入的字数为::::::" + ele.value.length; }
HmL事件必指HTML文件状志改变时触发的、用户可以捕获的事件,本部分介绍的常用的HTML事件包括onload窗口加载事件、onunload窗口离开事件、onresize 改变窗口大小触发的事件、onabort 中断事件、onerror异常事件、onreset 按下重置按钮事件、onsubmit按下提交按钮事件等。
onload事件并不是在窗口加载过程中执行,而是在页面包括页面中的图片、插件、控件、Applet小应用等内容全部下载完成后执行。onload 事件一般在
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <title>JavaScript基础 - 04 - DOM事件</title> <meta name="description" content="图灵斯顿俱乐部--IT前端中级课程,JavaScript基础 - 04 - DOM事件,报名微信:hututu52533" /> <meta name="viewport" content="width=device-width, initial-scale=1"> <style> </style> </head> <body onload="alert('进入页面了!!!')"> <script> </script> </body> </html>
这段代码就是在
onunload 事件在窗口离开时触发,窗口离开的行为包括关闭浏览器窗口、通过地址处或收藏夹前往其他页面、单击“返回”、“前进”、 “刷新”、“主页”其中一个按钮、单击一个前往其他页面的URL链接等。在JavaScript中,当用window.open打开个页面或重新赋予location.href的值等情况下触发。onunload 事件多用在
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <title>JavaScript基础 - 04 - DOM事件</title> <meta name="description" content="图灵斯顿俱乐部--IT前端中级课程,JavaScript基础 - 04 - DOM事件,报名微信:hututu52533" /> <meta name="viewport" content="width=device-width, initial-scale=1"> <style> </style> </head> <body onunload="onunloadHandle('我悄悄的走了不带走一片云彩!')" onload="alert('我静悄悄的来了!')"> <script> function onunloadHandle(str) { alert(str) } </script> </body> </html>
一般多用于,当用户关闭浏览器时,将页面中的全局变量废除。
onresize事件在当用户或者脚本更改窗口或框架大小时触发。onresize事件也需要在
function resize() { document.getElementById("resizeW").innerText = window.outerWidth; document.getElementById("resizeH").innerText = window.outerHeight; }
onabort事件只有页面在加载img图像元素的过程中发生中断才会触发。onabort事件添加在标签中,示例代码如下:
<img name='imgName' src="imgSrc" onabort="abortHandle()">
function abortHandle() { alert("图片加载失败了T。T"); }
当窗口中JavaScript存在异常时,会触发onerror事件。onerror 事件是window对象的属性,需要在JavaScript中使用window onerror指定其事件处理函数。使用onerror 事件以方便地获取各种错误信息,onerror 事件有3个默认的参数,分别是错误信息、错误页的URL、错误行号。例如在如下所示的代码中,在JavaScript中使用了一个未定义的变量使用onerror事件可以捕获到这个错误,并将详细信息获得。
onreset 事件一般在form表单被重置时触发使用。代码如下:
<form onreset="window.alert('表单将会被重置')"> 文字内容: <input type="text" name="txtContent" /> <input type="reset" value="重置" /> </form>
onsubmit事件在一个表单被提交时触发。代码如下:
<form onreset="window.alert('表单将会被重置')" onsubmit="return submitHandle()"> 文字内容: <input type="text" name="txtContent" /> <input type="reset" value="重置" /> </form>
function submitHandle() { alert("登陆的用户名是:" + document.getElementById('userName').value); }
变动事件是指由于光标位置的改变引起的状态的改变。常用的变动事件有onblur拾取焦点事件、onfocus获得焦点事件和onchange值改变时触发的事件。
onblur事件在得到焦点的对象失去焦点时触发。例如,在用户输入文本框信息后,当文本框失去焦点时,检验文本是否为空。其现方法如下:
<div> onblur 失去焦点事件 <input type="text" onblur="onblurHandle(this)" /> </div>
function onblurHandle(ele) { if (ele.value.trim().length === 0) { console.log("填写的信息不能为空"); } else { alert("输入的内容是" + ele.value) } }
onfocus 事件在未获得焦点的对象获得焦点时触发。例如,文本框获得焦点时候,边框变成蓝色,示例代码如下:
<div> onfocus 获得焦点事件 <input type="text" onfocus="onfocusHandle(this)" /> </div>
function onfocusHandle(ele) { ele.style.border = "5px solid blue"; }
onchange事件只在事件对象的值发生改变并且事件对象失去焦点时触发。看上面的onblur示例代码,如果使用onblur事件,文本框每一次失去焦点 都会触发onblur事件,继而执行其事件处理函数,即使用户没有对数据进行任何修改,事件处理函数也会执行。如果不希望每次失去焦点时都触发事件,要求只是在用户对文本框的值进行修改后,失去焦点时触发,可以使用onchange事件。将代码中文本框的onblur事件去掉,更改为onchange 事件(修改如下所示),事件处理函数不进行任何修改,用户在未对文本框的值进行任何修改时,事件处理函数不会执行。
<input type="text" onchange="onchangeHandle(this)" />
onchange事件多用于监听用户是否更改下拉列表的选择。实现的多级下拉列表联动的方法中,就是使用select 元素的onchange事件,判断用户是否对选择的值进行更改,进而实现下拉列表的动态改变。在select元素中,使用onchange 的方法与在文本框中使用方法相同,只需要在select标记中添加onchange事件及其事件处理函数。
<select name="sltName" onchange="changeHandle()">
本节课主要是以大量实例的形式介绍了JavaScript事件处理的概念,然后分别介绍了JavaScript的各种类型的事件,包括鼠标事件、键盘事件、HTML:事件、变动事件,同时详细介绍了各种事件触发的条件、发生过程和驱动机制等,并通过大量的实例,说明各种事件在实际应用中具体的使用方法。由于JavaScript 是种事件驱动的脚本语言, 事件处理 也是实际JavaScript编程中频繁使用的机制,因此本节课的内容需要熟练掌握。做大量的练习。
手写一个登陆页面,要求做到用户名、密码判断不能为空,可以提交和重置表单数据。
手写一个文章输入页面,要求做到标题不能为空,文本内容在输入字符时获取当前文本内容长度。
所有课件中的实例,都必须手把手的敲一边。
所有作业提交到javascript-learning\04-DOM事件自己的分支下。周日上课时检查
element.onclick = function() {}
让我们看一个简单的例子。前面您已经见到过很多事件和事件监听器,现在我们概括一下以巩固我们的知识。在接下来的例子中,我们的页面中只有一个 button,按下时,背景会变成随机的一种颜色。
<button>Change color</button>
JavaScript代码如下所示:
var btn = document.querySelector('button'); function random(number) { return Math.floor(Math.random()*(number+1)); } btn.onclick = function() { var rndCol = 'rgb(' + random(255) + ',' + random(255) + ',' + random(255) + ')'; document.body.style.backgroundColor = rndCol; }
我们使用btn变量存储 button,并使用了Document.querySelector()函数。我们也定义了一个返回随机数字的函数。代码第三部分就是事件处理器。btn变量指向 button 元素,在 button 这种对象上可触发一系列的事件,因此也就可以使用事件处理器。我们通过将一个匿名函数(这个赋值函数包括生成随机色并赋值给背景色的代码)赋值给“点击”事件处理器参数,监听“点击”这个事件。只要点击事件在<button>元素上触发,该段代码就会被执行。即每当用户点击它时,都会运行此段代码。
btn
Document.querySelector()
<button>
<div id="ear">Click me</div> <div id="display"></div> <script> var ear = document.getElementById('ear'); ear.addEventListener("click", listener, false); function listener() { document.getElementById('display').innerHTML = "blah blah"; } </script>
注意addEventListener是由浏览器提供的 api, 并非 JavaScript 原生 api. 用户触发 event 时, 浏览器会向 message queue 中加入 task, 并通过 Event Loop 执行 task 实现回调的效果.拓展阅读:
message queue
1、可以绑定多个监听函数,而DOM0级只能绑定一个监听函数。2、提供了移除的方法,但对于匿名函数无效。3、可以控制捕获还是冒泡,DOM0级只有冒泡
**
严格来说,上图还少了一个层级window,在顶层。
什么是事件冒泡?
看这段代码:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>冒泡事件的发生</title> </head> <style> #parent{ width: 200px; height: 200px; background-color: #999999; position: relative; } #child{ width: 80px; height: 80px; background-color: #669900; position: absolute; top: 200px; left: 100px; } </style> <body> <div id="parent"> 我是父元素 <div id="child"> 我是子元素 </div> </div> </body> <script> var parent = document.getElementById('parent') var child = document.getElementById('child') child.onclick = function (event) { console.log("我是个小孩子") } parent.onclick = function (event) { console.log("我是老纸啊") } </script> </html>
这里运行后显示成这样:
(关于子元素,父元素并不是传统视觉上的包含关系,具体要看html的代码结构)点击子元素:chrome 审查元素查看后看,触发了父类的点击事件。这个过程就是冒泡:由内而外触发,像水滴的水晕一样直到最后一层。
综上,现在举个例子看一下冒泡所带来的困扰:需求:点击父标签,子标签显示,点击其他空白区域,子标签隐藏。实现代码:**
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>冒泡事件的发生</title> </head> <style> #parent{ width: 200px; height: 200px; background-color: #999999; position: relative; } #child{ width: 80px; height: 80px; background-color: #669900; position: absolute; top: 200px; left: 100px; display: none; } </style> <body> <div id="parent"> 我是父元素 <div id="child"> 我是子元素 </div> </div> </body> <script> var parent = document.getElementById('parent') var child = document.getElementById('child') // child.onclick = function (event) { // console.log("我是个小孩子") // } parent.onclick = function (event) { console.log('显示啦') child.style.display = 'block' } window.onclick = function (event) { console.log('隐藏啦') child.style.display = 'none' } </script> </html>
点击后,点击父元素,子元素总是无法显示(曾经我找了好久啊)。这就是冒泡在作妖啊, 它先触发 parent点击——再触发window点击导致子元素显示之后,又迅速隐藏了。
如何解决冒泡所带来的困扰呢——阻止冒泡!标准的W3C 方式:e.stopPropagation();这里的stopPropagation是标准的事件对象的一个方法,调用即可非标准的IE方式:ev.cancelBubble=true; 这里的cancelBubble是 IE事件对象的属性,设为true就可以了通常我们会封装这样一个函数:(这一段参考了链接代码的)
function stopBubble(e) { //如果提供了事件对象,则这是一个非IE浏览器 if ( e && e.stopPropagation ) //因此它支持W3C的stopPropagation()方法 e.stopPropagation(); else //否则,我们需要使用IE的方式来取消事件冒泡 window.event.cancelBubble = true; }
下面我们尝试下~~
parent.onclick = function (event) { console.log('显示啦') child.style.display = 'block' stopBubble(event) }
点击父元素:运行看看子元素显示出啦啦,也没有触发window的点击函数哈,这样就完美的解决了冒泡的困扰。。。。。
e.stopImmediatePropagation()如果注册了多个监听函数,则一并阻止冒泡。e.currentTarget 绑定时间的对象,始终与this相同。e.target 触发事件的是哪个元素,就显示哪个元素对象。
e.stopImmediatePropagation()
e.currentTarget
e.target
1、mouseenter/mouseleave把冒泡机制阻止了。2、mouseenter/mouseleave运用了relatedTarget属性(e.relatedTarget既不是目标元素,也不是目标元素的子元素)。
mouseenter/mouseleave
relatedTarget
e.relatedTarget
事件名称 target属性 relatedTarget属性 focusin 接受焦点的节点 丧失焦点的节点 focusout 丧失焦点的节点 接受焦点的节点 mouseenter 将要进入的节点 将要离开的节点 mouseleave 将要离开的节点 将要进入的节点 mouseout 将要离开的节点 将要进入的节点 mouseover 将要进入的节点 将要离开的节点 dragenter 将要进入的节点 将要离开的节点 dragexit 将要离开的节点 将要进入的节点
自定义事件不是由DOM原生触发的,它的目的是让开发人员创建自己的事件。Event() 最简单的就是使用Event()构造函数。CustomEvent() 如果需要在触发事件的同时,传入指定的数据,需要使用CustomEvent构造函数生成自定义的事件对象。用this.dispatchEvent(customEvent(this))触发。
Event()
CustomEvent()
this.dispatchEvent(customEvent(this))
var eve = new Event('custome') // 注册事件 dom.addEventListener('custome', function() { // 绑定事件名称 console.log('我是自定义事件') }) dom.dispatchEvent(eve) // 通过dispatchEvent 来触发事件
拓展讲下--->
addEventListener(type,fun,bool)是监听一个事件,当触发事件时,执行函数,那么什么时候触发事件呢,当监听到dispatchEvent(type)时,触发
addEventListener(type,fun,bool)
dispatchEvent是发布事件的意思,在学习three.js源码时候看到这样一段加载vtk文件的代码
dispatchEvent
// 构造函数 THREE.VTKLoader = function () { THREE.EventDispatcher.call( this ); // 继承自监听器,使这个类有监听的功能 }; // VTKLoader的原型函数,里面包含了VTKloader的成员函数,成员变量的定义 THREE.VTKLoader.prototype = { // 构造函数 constructor: THREE.VTKLoader, // 加载函数,url表示要加载的vtk文件的url路径,callback表示加载完成后要调用的后续处理函数,这里是异步操作,加载需要一个过程,不能将程序阻塞在这里,所以需要异步回调 load: function ( url, callback ) { // 将类自身保存在scope中,scope表示域的意思,这里是为了避免this的歧义,因为,每一个地方使用this,其意义不一样。 var scope = this; // ajax 异步请求 var request = new XMLHttpRequest(); // 加载完成的监听器,加载完成后,将调用第二个参数定义的回调函数 request.addEventListener( 'load', function ( event ) { // 对服务器加载下来的数据进行解析,后面详细解释 var geometry = scope.parse( event.target.responseText ); // 解析完成后,发一个load事件,表示数据解析完成 scope.dispatchEvent( { type: 'load', content: geometry } ); // 如果设置了回调函数,那么调用回调函数 if ( callback ) callback( geometry ); }, false ); // 加载过程中,向自身发送进度progress信息,信息中包含已经加载的数据的字节数和文件总共的字节数,通过两者的百分比能够了解加载进度。 request.addEventListener( 'progress', function ( event ) { // 发送正在加载的消息,两个参数分别是已经加载了多少字节,总共多少字节 scope.dispatchEvent( { type: 'progress', loaded: event.loaded, total: event.total } ); }, false ); // 加载出错的监听器,加载的过程也可能出错,这里如果出错,进行错误处理, request.addEventListener( 'error', function () { // 加载出错之后需要发布的错误消息, scope.dispatchEvent( { type: 'error', message: 'Couldn\'t load URL [' + url + ']' } ); }, false ); // 初始化 HTTP 请求参数,例如 URL 和 HTTP 方法,但是并不发送请求。 request.open( 'GET', url, true ); //发送 HTTP 请求,开始下载 request.send( null ); }, // parse函数在上面调用过,主要负责解析数据的功能,我们将在后面详细介绍解析函数,这里就不介绍了。 parse: function ( data ) { var geometry = new THREE.Geometry(); function vertex( x, y, z ) { geometry.vertices.push( new THREE.Vector3( x, y, z ) ); } function face3( a, b, c ) { geometry.faces.push( new THREE.Face3( a, b, c ) ); } function face4( a, b, c, d ) { geometry.faces.push( new THREE.Face4( a, b, c, d ) ); } var pattern, result; // float float float pattern = /([\+|\-]?[\d]+[\.][\d|\-|e]+)[ ]+([\+|\-]?[\d]+[\.][\d|\-|e]+)[ ]+([\+|\-]?[\d]+[\.][\d|\-|e]+)/g; while ( ( result = pattern.exec( data ) ) != null ) { // ["1.0 2.0 3.0", "1.0", "2.0", "3.0"] vertex( parseFloat( result[ 1 ] ), parseFloat( result[ 2 ] ), parseFloat( result[ 3 ] ) ); } // 3 int int int pattern = /3[ ]+([\d]+)[ ]+([\d]+)[ ]+([\d]+)/g; while ( ( result = pattern.exec( data ) ) != null ) { // ["3 1 2 3", "1", "2", "3"] face3( parseInt( result[ 1 ] ), parseInt( result[ 2 ] ), parseInt( result[ 3 ] ) ); } // 4 int int int int pattern = /4[ ]+([\d]+)[ ]+([\d]+)[ ]+([\d]+)[ ]+([\d]+)/g; while ( ( result = pattern.exec( data ) ) != null ) { // ["4 1 2 3 4", "1", "2", "3", "4"] face4( parseInt( result[ 1 ] ), parseInt( result[ 2 ] ), parseInt( result[ 3 ] ), parseInt( result[ 4 ] ) ); } geometry.computeCentroids(); geometry.computeFaceNormals(); geometry.computeVertexNormals(); geometry.computeBoundingSphere(); return geometry; } }
注意这里
request.addEventListener( 'load', function ( event ) { var geometry = scope.parse( event.target.responseText ); scope.dispatchEvent( { type: 'load', content: geometry } ); if ( callback ) callback( geometry ); }, false );
这里event.target.responseText是服务器返回的文本数据,也就是vtk文件里的所有数据,我们通过scope.parse方法将其转换为geometry。
转换完后,我们会通过dispathEvent向自身发送一个加载完成的消息,消息中返回了geometry几何体。这个几何体是可以和Mesh合体,最终显示在场景中的。最后,如果callback不为null的话,那么我们就调用这个回调函数。在这个回调函数中,会做一些模型加载完成后,应该做的事情,例如,将模型放到某一个位置。
更多详情戳这里3D模型的加载与使用
这里我们主要说dispatchEvent
dispatchEvent是作为高级浏览器(如chrome、Firfox等)的事件触发器来使用的,那么什么是事件触发器?就是触发事件的东西。可能有人觉得有点莫名其妙,触发事件不是在交互中 被触发的吗?的确,通常情况下,事件的触发都是由用户的行为如点击、刷新等操作实现,但是,其实有的情况下,事件的触发必须又程序来实现,比如ajax框架的一些自定义事件。正如事件的绑定一样,对于浏览器而言,绑定事件分为高级浏览器和IE浏览器两派,事件触发器也是分为高级浏览器和IE两派,而dispatchEvent正是用于高级浏览器的事件触发
<!-- Author: AlexZ33 --> <!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8"> <title>dispatchEvent</title> </head> <body> </body> <script type="text/javascript"> //document上绑定自定义事件oneating document.addEventListener('oneating', function (event) { alert(event.mingzi+','+event.message); }, false); //创建event的对象实例。 var event = document.createEvent('HTMLEvents'); // 3个参数:事件类型,是否冒泡,是否阻止浏览器的默认行为 event.initEvent("oneating", true, true); /*属性,随便自己定义*/ event.mingzi = 'hello,我是鲸鱼'; event.message = '我是个书虫'; //触发自定义事件oneating document.dispatchEvent(event); </script> </html>
dispatchEvent大概就是这三步,上面的例子结果是:在页面载入的时候,会弹出提示框,也就是触发了oneating这个自定义事件。
var fireEvent = function(element,event){ if (document.createEventObject){ // IE浏览器支持fireEvent方法 var evt = document.createEventObject(); return element.fireEvent('on'+event,evt) } else{ // 其他标准浏览器使用dispatchEvent方法 var evt = document.createEvent( 'HTMLEvents' ); evt.initEvent(event, true, true); return !element.dispatchEvent(evt); } };
document.creatEventObject()是IE创建event对象实例的方法,和document.creatEvent('HTMLEvents')在非IE主流浏览器下的作用相同,fireEvent是IE下的事件触发器,与dispatchEvent在非IE主流浏览器下作用相同。
document.creatEventObject()
document.creatEvent('HTMLEvents')
一般而言,异步任务有以下三种类型: 1、普通事件,如click、resize等 2、资源加载,如load、error等 3、定时器,包括setInterval、setTimeout等同步变异步是性能优化的手段之一,如利用定时器对数组进行分块。
clientX/Y与x/y clientX/Y表示鼠标指针在可视区域中的水平和垂直坐标。screenX/Y screenX/Y表示鼠标指针相对于屏幕的水平和垂直坐标PageX/Y与layerX/Y pageX/Y表示相对于页面的水平和垂直坐标,它与clientX/clientY的区别是不随滚动条的位置变化。offsetX/Y offsetX/Y表示相对于定位父级的水平和垂直坐标。当页面无定位元素时,body是元素的定位父级。由于body的默认margin是8px,所以offsetX/Y与clientX/Y差(8,8)。
clientX/Y与x/y
clientX/Y
screenX/Y
PageX/Y
layerX/Y
pageX/Y
offsetX/Y
offsetX/Y与clientX/Y
<div id="box" style="height:100px;width:300px;background:pink;"></div> <script> var oBox = document.getElementById('box'); oBox.onmousemove=function(e){ e = e || event; oBox.innerHTML = 'clientX:' + e.clientX +';clientY:'+e.clientY + '<br>offsetX:' + e.offsetX + ';offsetY:' + e.offsetY; } </script>
系统为了防止按键误被连续按下,所以在第一次触发keydown事件后,有500ms的延迟,才会触发第二次keydown事件。 [注意]类似的,keypress事件也存在500ms的时间间隔。
keydown
keypress
500ms
如果用户一直按键不松开,就会连续触发键盘事件,触发的顺序如下1、keydown 2、keypress 3、keydown 4、keypress 5、(重复以上过程) 6、keyup。
keyup
7个变动事件,浏览器兼容性都不是太好。说的过得去就是DOMNodeInserted、DOMNodeRemoved和DOMSubtreeModified这三个事件,不兼容IE8-浏览器。剪贴板操作包括剪切(cut)、复制(copy)和粘贴(paste)这三个操作,快捷键分别是ctrl+x、ctrl+c、ctrl+v。当然也可以使用鼠标右键菜单进行操作。如果DOM结构发生变化,触发的是变动事件,如果文本框中的文本发生变化,触发的是文本事件。
DOMNodeInserted
DOMNodeRemoved
DOMSubtreeModified
说起文本变化,最先想到的可能就是change事件。 对于<input>和<textarea>元素,在它们失去焦点且value值改变时触发;对于<select>元素,在其选项改变时触发。
<input>
<textarea>
<select>
DOM3级事件引人了一个新事件——textInput,用来替代keypress事件。当用户在可编辑区域中输入字符时,就会触发这个事件。 [注意]该事件只支持DOM2级事件处理程序,且只有chrome和safari浏览器支持。 由于<input type="range">的游标并不是可编辑区域,所以,textInput事件对游标变化无作用。
textInput
<input type="range">
文本事件中,除了textInput事件,还有一个input事件。HTML5新增了一个input事件,只要输入框内容发生变化就会立即触发,但通过JS改变value时不会触发。所以这事件与change事件的区别就是不需要移除焦点就可以触发。该事件可以在chrome/safari/firefox/IE9浏览器中,实时监测游标的变化。
如果页面从浏览器缓存加载,并不会触发load事件,图像和框架iframe也可以触发load事件。要在指定图像的src属性之前先指定事件,图像是从设置src属性之后开始下载。script元素也可以触发load事件,以便开发人员确定动态加载的JS文件是否加载完毕。与图像不同,只有在设置了script元素的src属性并将该元素添加到文档后,才会开始下载JS文件。换句话说,指定src属性和指定事件处理程序的先后顺序不重要。类似地,link元素可以触发load事件,且无兼容性问题。与script类似,在未指定href属性并将link元素添加到文档之前也不会开始下载样式表。
load事件在加载成功时触发,而error事件与之正相反,在加载失败时触发。凡是可以触发load事件的元素,同样可以触发error事件。任何没有通过try-catch处理的错误都会触发window对象的error事件。error事件可以接收三个参数:错误消息、错误所在的URL和行号。多数情况下,只有错误消息有用,因为URL只是给出了文档的位置,而行号所指的代码行既可能出自嵌入的JS代码,也可能出自外部的文件。要指定onerror事件处理程序,可以使用DOM0级技术,也可以使用DOM2级事件的标准格式。这个事件处理程序是避免浏览器报告错误的最后一道防线。理想情况下,只要可能就不应该使用它。只要能够适当地使用try-catch语句,就不会有错误交给浏览器,也就不会触发error事件。图像也支持error事件。只要图像的src特性中的URL不能返回可以被识别的图像格式,就会触发error事件。此时的error事件遵循DOM格式,会返回一个以图像为目标的event对象。发生error事件时,图像下载过程已经结束,也就是不能再重新下载了。但是,可以在error事件中,重新设置图像的src属性,指向备用图像的地址。
元素加载中止时,(如加载过程中按下ESC键,停止加载),触发该事件,常用于图片加载。
与load事件对应的是unload事件,该事件在文档被完全卸载后触发,刷新页面时,也会触发该事件。在卸载页面的时候,会导致“空事件处理程序”的发生。“空事件处理程序”是指内存中存留的过时不用的事件处理程序,它们是造成Web应用程序内存与性能问题的主要原因。一般来说,最好的做法是在页面卸载之前,先通过onunload事件处理程序移除所有事件处理程序。因此,只要是通过onload事件处理程序添加的东西,最后都应该通过onunload事件处理程序将它们移除。
beforeunload事件在关闭网页或刷新网页时触发。它一般地用来防止用户不小心关闭网页。
DOMContentLoaded事件则在形成完整的DOM树之后就会触发,而不理会图像、JS文件、CSS文件或其他资源是否下载完毕。与load事件不同,DOMContentLoaded支持在页面下载的早期添加事件处理程序,这也就意味着用户能够尽早地与页面进行交互。[注意]网页的JS脚本是同步执行的,所以定义DOMContentLoaded事件的监听函数,应该放在所有脚本的最前面。否则脚本一旦发生堵塞,将推迟触发DOMContentLoaded事件。
DOMContentLoaded
readystatechange事件发生在Document对象和XMLHttpRequest对象,它们的readyState属性发生变化时触发。
readystatechange
readyState
activeElement document.activeElement属性用于管理DOM焦点,保存着当前获得焦点的元素。
activeElement
document.activeElement
元素获得焦点的方式有4种,包括页面加载、用户输入(按tab键)、focus()方法和autofocus属性。【1】页面加载 默认情况下,文档刚刚加载完成时,document.activeElement中保存的是body元素的引用。文档加载期间,document.activeElement的值为null。【2】用户输入(按tab键) 用户通常可以使用tab键移动焦点,使用空格键激活焦点。比如,如果焦点在一个链接上,此时按一下空格键,就会跳转到该链接。1、如果tabindex=-1,tab键跳过当前元素。2、如果tabindex=0,表示tab键将遍历当前元素。如果一个元素没有设置tabindex,默认值就是0。3、如果tabindex大于0,表示tab键优先遍历。值越大,就表示优先级越小 下列代码中,使用tab键时,button获得焦点的顺序是2、5、1、3
<button tabindex= "3">1</button> <button tabindex= "1">2</button> <button tabindex= "0">3</button> <button tabindex= "-1">4</button> <button tabindex= "2">5</button> </div> <script> box.onkeyup = function(){ document.activeElement.style.background = 'pink'; } </script>
hasFocus() document.hasFocus()方法返回一个布尔值,表示当前文档之中是否有元素被激活或获得焦点。通过检测文档是否获得了焦点,可以知道是不是正在与页面交互。
hasFocus()
document.hasFocus()
在页面获得或失去焦点时触发。利用这些事件并与document.hasFocus()方法及 document.activeElement属性配合,可以知晓用户在页面上的行踪。 焦点事件共包括下面4个:blur blur事件在元素失去焦点时触发。这个事件不会冒泡。focus focus事件在元素获得焦点时触发。这个事件不会冒泡。focusin focusin事件在元素获得焦点时触发。这个事件与focus事件等价,但它冒泡。focusout focusour事件在元素失去焦点时触发。这个事件与blur事件。
blur
focus
focusin
focusout
学习如何用 JavaScript 操作 DOM 样式
再次理解 JavaScript 的事件机制,并了解事件代理
我们顺便学习一个新知识:定时
JavaScript基础 -- DOM事件
概要
事件概念、基础、常用事件
要了解事件处理,首先需要知道的一个概念就是“事件”。
“事件”本身是一个抽象的概念,也是一个对象, 它是表现另外的对象状态变化的对象。日常生活中,“事件”随处可见。例如,按下电脑的电源键电脑就开机了。在这里“按下电脑的电源键”就是一个事件,这个事件的结果就是“电脑开机了”,看到的就是电脑处理“按下电源键”这个事件的结果,而这个处理的过程就是本书要说的事件处理。
事件处理是面向对象编程的一个重要概念,而JavaScript是一种基于对象 与事件驱动的脚本语言,因此,事件处理在JavaScript中也是一个重要概念。简单地说,“事件处理” 就是当对象的状态改变时( 电脑的电源键由正常改变为被按下),对象应对这种改变的动作(电脑对电源键状态的改变进行的处理过程)。对事件进行处理的程序或函数称为“事件处理”。
在JavaScript中,鼠标、键盘、文档的状态改变(动作)称为事件;由鼠标、键盘、文档引发的一系列的程序动作, 称为事件驱动;对发生的事件进行相应处理的程序或函数,称为事件处理函数。JavaScript 的事件处理函数使用function函数的形式定义,方法如下:
其中,funcName 是事件处理函数的函数名,这是必需的(某些情况下用户可以定义匿名的事件处理函数,window.onload-function()...})。事件处理函数可以有()至多个参数,用户可以根据需要指定。指定某个事件的事件处理函数的方法是:事件=事件处理函数名()。例如,在如下所示的代码中,“ 单击”按钮的onclick事件有一个名为clkHandle的事件处理函数。
在上述代码中,指定了“单击”按钮的onclick事件及其名为ckHande()的事件处理函数。在JavaScript中,指定某个事件的事件处理函数的方法,就是给某个HTML元素的事件名属性赋值为函数的函数名。上述代码运行时,单击页面中的“单击”按钮,会弹出如下图所示的提示信息。
![image.png](https://cdn.nlark.com/yuque/0/2020/png/686528/1582171070501-95aee5a6-9332-4ab2-8c7e-d42246057838.png#align=left&display=inline&height=132&name=image.png&originHeight=264&originWidth=1036&size=41563&status=done&style=none&width=518)
在JavaScript中,事件类型分为很多中,如鼠标事件、键盘事件、HTML事件、变动事件。本课程将对这些事件一一叙述、娓娓道来。
鼠标事件
鼠标事件是指鼠标状态的改变,包括鼠标在移动过程中、单击过程中、拖动过程中等有鼠标状态改变触发的事件。常用的鼠标事件有onclick单击事件、ondblClick 双击事件、onmouseout鼠标离开事件、onmouseover鼠标移到上方事件、onmouseup鼠标放开事件、onmousedown鼠标按下事件和onselect选中事件等。
onclick 单击事件
onclick 事件在鼠标单击某元素时触发。单击是指鼠标停留在对象上,按下鼠标按键,没有移动鼠标而放开鼠标按键这一个完整的过程。我们在以后的开发过程中,最常用也是最常碰到的事件处理就是onclick鼠标单击事件,从之前的课程中学员们应该有所体会。
ondblClick 双击事件
ondblClick事件在鼠标双击某元素时触发。双击事件是在较短的时间内,连续两次完成鼠标单击事件。
例如,要求双击ul-->li 中的某一行时, 此行显示与其他行不同的背景色(整个页面的色是白色),具体实现方法如代码所示:
在适当的地方正确使用鼠标双击事件可以提高页面的显示效果,改善用户体验。
onmouseover 鼠标滑入事件
onmousovser事件在鼠标进入对象范围(移到对象上方)时触发。文本框所在元素li的HTML,代码如下:
当鼠标进入单元格时,触发onmouseover事件,调用名称为modStyle的事件处理函数,完成对单元格样式的更改。onmouseover 事件可以应用在所有的HTML页面元素中,例如,鼠标经过文字上方时,显示效果为“鼠标来到了我的上面^_^”,鼠标离开后,显示效果为“鼠标从我上面离开了T。T”。其实现方法如下:
onmouseout 鼠标离开事件
onmouseout事件在鼠标离开对象时触发。onmouseover事件通常与onmouseover事件共同使用改变对象的状态。
onmousedown 鼠标按下事件
onmousedown事件在用户把鼠标放在元素上按下鼠标是触发。下面我们来看下下面这个演示demo:
onmouseup 鼠标放开事件
onmouseup事件在用户把鼠标放在对象上鼠标按键被按下的情况下,放开鼠标键时触发。如果接收鼠标键按下事件的对象与鼠标键放开时的对象不是同一个对象,那么onmouseup事件不会触发。onmousedown 事件与onmouseup事件有先后顺序,在同一个对象上前者在先后者在后。onmouseup事件通常与onmousedown事件共同使用控制同一对象的状态改变。
我们继续刚刚的代码示例,添加onmouseup事件进入:
onselect 选中事件
onselect事件在文本框或是文本域的内容被选中时(选中的部分高亮显示)触发。onselect事件的具体过程是从鼠标按键被按下,到鼠标开始移动并选中内容的过程。这个过程并不包括鼠标键的放开。
例如在一一个 HTML页面中,当用户选择文本框中的文字时,在div中显示用户选中的文字内容。其实现方法如下:
[MDN] selection 详解
键盘事件
键盘事件是指键盘状态的改变,常用的键盘事件有onkeydown 按键事件、onkeypress 按下键事件和onkeyup
放开键事件等。
onkeydown 键盘事件
onkeydown事件在键盘的按键被按下时触发。onkeydown事件用于接收键盘的所有按键(包括功能键)被按下时的事件。onkeydown 事件与onkeypress事件都在按键按下时触发,但是两者有区别,详情下面onkeypress和onkeyup的讲解。
例如,在用户输入信息的界面中,为方便用户使用,通常情况下,当用户按回车键时,触发页面登陆、提交等等功能。
onkeypress 按下事件
onkeypress事件在键盘的按键被按下时触发。onkeypress事件与onkeydown事件两者有先后顺序,onkeypress事件是在onkeydown事件之后发生的。此外,当按下键盘上的任何一个键时,都会触发onkeydown事件;但是onkeypres事件只在按下键盘上的任字符键(如A~Z、数字键)时触发,但是单独按下功能键(F1~F12)、Ctrl键、Shift键、Alt键等,不会触发onkeypress事件。
onkeydown事件与onkeypress事件执行的先后顺序,其代码如下:
onkeyup 放开事件
onkeyup事件在键盘的按键被按下然后放开时触发。
例如,页面中要求用户输入内容后,使用onkeyup事件,获取文本框中输入内容的长度,示例如下:
HTML事件
HmL事件必指HTML文件状志改变时触发的、用户可以捕获的事件,本部分介绍的常用的HTML事件包括onload窗口加载事件、onunload窗口离开事件、onresize 改变窗口大小触发的事件、onabort 中断事件、onerror异常事件、onreset 按下重置按钮事件、onsubmit按下提交按钮事件等。
onload 窗口加载事件
onload事件并不是在窗口加载过程中执行,而是在页面包括页面中的图片、插件、控件、Applet小应用等内容全部下载完成后执行。onload 事件一般在
标记中添加。例如,在用户打开页面时,将光标自动停放在“用户名”文本框中,其实现方法如下:这段代码就是在
标签中添加onload事件,当加载时弹出alert事件。一般onload事件多用于页面加载完毕后,用户进行操作之前的一些内部处理,如光标定位、页面显示效果更改、读取用户cookie信息等等。onunload 窗口离开事件(现在在多数浏览器中,已被停止使用)
onunload 事件在窗口离开时触发,窗口离开的行为包括关闭浏览器窗口、通过地址处或收藏夹前往其他页面、单击“返回”、“前进”、 “刷新”、“主页”其中一个按钮、单击一个前往其他页面的URL链接等。在JavaScript中,当用window.open打开个页面或重新赋予location.href的值等情况下触发。onunload 事件多用在
或