js权威指南之事件和事件处理

1 基本事件处理
事件句柄和this关键字:
在事件句柄被调用时,文档元素是作为产生事件的元素的方法调用的,所以关键字this引用了那个目标元素
事件句柄的作用域:
函数在定义它们的作用域中运行,而不在调用它们的作用域中运行。在为标记的HTML属性设置js代码串时,其实是定义了一个函数,而以这种方式定义的事件处理函数的作用域与用常规方法定义的全局js函数不同。这意味着定义为HTML属性的事件句柄所执行的作用域和其他函数的作用域不同
定义为HTML属性的事件句柄的作用域链头是调用对象,传递给事件句柄的所有参数都是在这里定义的,它们就和事件句柄主体中声明的局部变量一样。但事件句柄的作用域链中的下一个对象却并非全局对象,而是触发事件句柄的对象。
例如    使用<input>标记在HTML表单中定义了一个Button对象,然后使用onclick属性定义了一个事件句柄。如果该事件句柄的代码使用了一个名为form的变量,那么该变量会被解析为Button对象的form属性。
在定义作为HTML属性的事件句柄时,最安全的方法是使这种句柄尽量简单。理想的方法是让它们只调用在别的地方定义的全局函数,并可能返回下面的结果:
        <script>function validateForm(){}</script>
        <form onsubmit = "return validateForm();">...</form>
这样一个简单的事件句柄仍旧用一个不寻常的作用域链执行,但为了保持代码简短,尽量避免长作用域链带来的麻烦。由于函数在定义它们的作用域中运行,而不在调用它们的作用域中运行。所以即使从不寻常的作用域中调用了validateForm()方法,仍旧可以在它自己的全局作用域中执行,而不会产生任何混淆。
最后,记住,关于事件句柄作用域的完整讨论只适用于定义为HTML属性的事件句柄。如果把一个函数赋予适当的js事件句柄属性来设置事件句柄,那么根本不涉及特殊的作用域链,函数在定义它的作用域中执行,这几乎总是全局作用域,除非它是一个嵌套函数,在这种情况下,作用域链又变得有趣了。

2  2级DOM中的高级事件处理
事件传播:
在0级DOM事件模型中,浏览器把事件分派给发生事件的文档元素。如果那个对象具有适合的事件句柄,就运行这个句柄,除此之外不用执行其他操作。
在2级DOM这种高级事件模型中,当事件发生在文档元素上时,目标事件句柄被触发。此外目标的每个祖先元素也有机会处理那个事件。事件传播分三个阶段
一、捕捉阶段,事件从Document对象沿着文档树向下传播给目标节点。如果目标的任何一个祖先专门注册了捕捉事件句柄,那么在事件传播过程中就会运行这些句柄。
二、 直接注册在目标上的适合的事件句柄将运行
三、起泡阶段,事件从目标元素向上传播回或起泡回Document对象的文档层次。 
这种事件传播可帮助事件处理代码中心化,1级DOM展现所有的文档元素,允许事件在任何元素上发生。这意味着注册事件句柄的地方比老式的0级事件模型多得多。
假定想为每个<p>标记都注册一个onmouseover事件句柄,只在Document对象上注册一个onmouseover,然后在事件传播的捕捉或起泡阶段处理这些事件即可。
关于事件传播,有一个重要细节。在0级模型中,只能为特定对象的特定类型的事件注册一个事件句柄。但在2级模型中可为特定对象的特定类型事件注册任意多个,处理器函数。这同样适用于事件目标的祖先,它们的处理函数将在事件传播的捕捉阶段或起泡阶段调用。
事件句柄的注册:
2级事件模型中,可以调用对象的addEventListener()方法为特定元素注册事件句柄。
第一个参数是要注册句柄的事件类型名
第二个参数是句柄函数
第三个参数是一个布尔值。若值为true,则指定的事件句柄将在事件传播的捕捉阶段用于捕捉事件。若为false,则事件句柄就是常规的,当事件直接发生在对象上,或发生在元素的子女上,又向上起泡到该元素时,该句柄将被触发。
在2级模型中,若给同一对象同一类型的事件注册了多个处理函数,那么在该类型的事件在那个对象上发生时,被注册的所有函数都将被调用,但函数的调用顺序不确定。

Event接口
当事件发生时,2级DOM API提供了事件的额外信息,作为传递给事件句柄的对象的属性。
Event
type:发生的事件的类型。该属性值是事件类型名,与注册事件句柄时使用的字符串值相同
target:发生事件的节点,可能与currentTarget不同
currentTarget:发生当前正在处理的事件的节点(如当前正在运行事件句柄的节点)。如果在传播过程的捕捉阶段或起泡阶段处理事件,这个属性的值就与target属性的值不同。
eventPhase:一个数字,指定当前所处的事件传播过程的阶段。它的值是常量,可能值包括Event.CAPTURE_PHASE,Event.AT_TARGET或Event.BUBBLING_PHASE
timeStamp:一个Date对象,声明了事件何时发生
bubbles:一个布尔值,声明该事件是否在文档树中起泡
cancelable:一个布尔值,声明该事件是否具有能用preventDefault()方法取消的默认动作
除了这7个属性,Event接口定义了两个方法,stopPropagation()和preventDefault(),前者阻止事件从当前正在处理它的节点传播。后者阻止浏览器执行与事件相关的默认动作。

UIEvent
UIEvent接口是Event接口的子接口,它定义的事件对象类型要传递给DOMFocusIn、DOMFocusOut和DOMActivate类型的事件。
view:发生事件的Window对象
detail:一个数字,提供事件的额外信息。对于click事件、mousedown事件和mouseup事件,这个字段代表点击的次数,1代表点击一次,2代表双击,3代表点击三次(注意,每次点击生成一个事件,但如果多次点击的间隔足够近,就可以用detail值说明它。简而言之,detail值为2的鼠标事件前面总是有一个detail值为1的鼠标事件)。对于DOMActivate事件,这个字段的值为1,表示正常激活,2表示超级激活,如双击鼠标或同时按下Shift键和Enter键

MouseEvent
MouseEvent接口继承Event接口和UIEvent接口的所有属性和方法,此外还定义了下列属性:
button:一个数字,声明在mousedown、mouseup和click事件中,哪个鼠标键改变了状态。值0、1、2分别代表左键、中间键和右键。这个属性只在鼠标键状态改变时使用,例如,在mousemove事件中,它不能用来汇报按键是否被按下并保持住了
altKey、ctrlKey、metaKey和shiftKey
这4个布尔值声明在鼠标事件发生时,是否按住了Alt键、Ctrl键、Meta键或Shift键。与button属性不同,这些键盘键属性对任何鼠标事件类型都有效。
clientX、clientY
这两个属性声明鼠标指针相对于客户区域或浏览器窗口的X坐标和Y坐标。注意,这两个坐标不考虑文档滚动,如果事件发生在窗口的顶部,无论文档滚动了多远,clientY都是0.
screenX、screenY
这两个属性声明了鼠标指针相对于用户显示器的左上角的X坐标和Y坐标。如果计划在鼠标事件所在地打开一个新浏览器窗口,这两个值非常有用
relatedTarget
该属性引用与事件的目标节点相关的节点。对于mouseover事件来说,它是鼠标移到目标上时所离开的那个节点。对于mouseout事件,它是离开目标时鼠标进入的节点。对于其他类型的事件来说,这个属性没有用。

混合事件模型
支持2级模型的浏览器将继续支持0级事件模型,这意味着可以在文档中使用混合事件模型。
浏览器传递给事件句柄一个事件对象,事件句柄是通过用0级模型设置HTML属性或JS属性注册的。在事件句柄定义为HTML属性时,它将隐式地转换成一个函数,该函数有一个参数,名为event。这意味着这样一个事件句柄可以用标识符event引用事件对象。

3 IE事件模型
IE事件模型介于0级模型和标准2级DOM模型之间,包括Event对象,该对象提供发生的事件的详细情况。但Event对象不是传递给事件句柄函数,而是作为Window对象的属性。IE模型支持起泡形式的事件传播,但不支持DOM模型的捕捉形式的事件传播(尽管IE5及其后的版本提供了专门的函数来捕捉鼠标事件)。在IE4中,注册事件句柄的方式与原始的0级模型注册方式相同,但IE5及其后版本中,可用专门但非标准的注册函数注册多个句柄。
IE Event对象
type :  字符串,声明发生的事件的类型,不带前缀"on"
srcElement : 发生事件的文档元素。与DOM Event对象的target属性兼容
button:  一个整数,声明被按下的鼠标键。值1、2、4分别表示左键、右键和中间键。如果按下了多个键,这些值将加在一起。若按下了多个键,这些值将加在一起
clientX、clientY:   声明事件发生时鼠标的坐标,其值是相对于包含窗口的左上角生成的。这些属性值和具有相同名字的2级DOM MouseEvent属性兼容
offsetX、offsetY:  声明鼠标指针相对于源元素的位置
altKey、ctrlKey和shiftKey :  声明发生鼠标事件时是否按住了alt,ctrl或shift键
KeyCode: 这个整数属性声明了keydown和keyup事件的键代码及keypress事件的Unicode字符。用String.fromCharCode()方法可以把字符代码转换成字符串
fromElement、toElement:  fromElement声明mouseover事件中鼠标移动过的文档元素。toElement声明mouseout事件中鼠标移到的文档元素
cancelBubble:  设为true可阻止当前事件进一步起泡到包容层次的元素。与DOM的Event对象的stopPropagation()方法相同
returnValue:   设为false可阻止浏览器执行与事件相关的默认动作。它可替代由事件句柄返回false的老方法。它等价于DOM的Event对象的preventDefault()方法

作为全局变量的IE Event对象
虽然IE事件模型在Event对象中提供了事件的详细情况,但IE只是把事件对象传递给使用非标准的attachEvent()方法注册的句柄,其他的事件句柄调用的时候没有参数。IE不把Event对象作为参数传递给事件句柄,而通过全局Window对象的event属性访问Event对象。
attachEvent和detachEvent与addEventListener和removeEventListener区别在于:
1由于IE事件模型不支持事件捕捉,因此attachEvent和detachEvent方法只有两个参数,即事件类型和句柄函数
2传递给IE方法的事件句柄名字应该包括一个"on"前缀
3用attachEvent注册的函数将被作为全局函数调用,而不是作为发生事件的文档元素的方法,也就是说,在attachEvent()注册的事件句柄执行时,关键字this引用的是Window对象,而不是事件的目标元素
4attachEvent允许同一个事件句柄函数注册多次。当指定类型的一个事件发生时,注册函数被调用的次数和它被注册的次数一样多

IE中的事件起泡
IE中的事件起泡和2级DOM事件模型中的事件起泡之间的差别在于停止起泡的方式。IE Event对象没有DOM Event对象具有的stopPropagation()方法,所以阻止事件起泡需把Event对象的cancelBubble属性设为true

捕获鼠标事件
要实现涉及到拖拽鼠标的任何用户接口,能够捕获鼠标事件以便能够正确处理鼠标拖拽而不管用户拖拽了什么,这一点是很重要的。在IE5及其后版本中,通过setCapture和releaseCapture方法来实现
setCapture和releaseCapture是所有HTML元素的方法。当在一个元素上调用setCapture时,所有后续的鼠标事件都被引导到这个元素,并且这个元素的句柄可以在这些事件起泡前处理它们。注意,这只对鼠标事件适用,并且包括所有和鼠标相关的事件:mousedown,mouseup,mousemove,mouseover,mouseout,click和dblclick
当调用setCapture的时候,鼠标事件专门分派,直到调用releaseCapture或者捕获被中断。如果web浏览器失去焦点,鼠标事件可能会中断,会出现一个alert()对话框,显示一个系统菜单,或者类似的情况。如果发生了某种这样的事情,setCapture调用所基于的元素会接收到一个onlosecapture事件,通知它不再会接收到捕获的鼠标事件
在大多数常见的情形中,setCapture调用来作为对一个mousedown事件的响应,以保证后续的mousemove事件能够被同一元素所接收。元素执行其拖拽操作来响应mousemove事件,并且调用releaseCapture()来响应一个捕获的mouseup事件

attachEvent和this关键字
attachEvent作为全局函数调用,而不是作为发生事件的文档元素的方法,这意味着,关键字this引用的是全局窗口对象。就其自身而言,这还不是个问题,但考虑到IE事件对象没有等价的DOM currentTarget属性,情况就变得复杂了。srcElement指定了产生这一事件的元素,但如果事件已经起泡,这可能和处理事件的元素有所不同
若想编写一个通用的可在任何元素上注册的事件句柄,并且如果这个句柄需要知道它注册于哪个元素上,就不能用attachEvent()来注册该句柄。必须使用0级事件模型来注册句柄或者围绕句柄定义一个包围函数并注册这个包围函数
      function genericHandler(){}
      var element = document.getElementByIdx_x_x("myelement");
      element.onmouseover = genericHandler;
      element.attachEvent("onmouseover",function(){genericHandler.call(element,event)});
使用0级API的问题是它不允许多个句柄函数被注册,并且使用闭包的问题在于它们会导致IE中的内在泄漏。

事件句柄和内存泄漏
正如8.8.4.2中所说,当使用嵌套函数作为事件句柄时,IE(至少到IE6)很容易遭受一种内在泄漏,如下:
function addValidationHandler(form){    //为一个表单添加事件句柄
      form.attachEvent("onsubmit",function(){return validate();});
}
当调用这个函数时,它为指定的表单元素添加一个事件句柄,这个事件句柄定义为一个嵌套函数,尽管函数本身没有引用任何表单元素,但作为闭包的一部分而捕获的它的作用域会引用。结果一个表单元素引用了一个js Function对象,并且这个对象通过其作用域链引用回表单对象。这种循环引用导致了IE中的内存泄漏
这一问题的解决方案是:在针对IE编程的时候,有意避免使用嵌套的函数。另一种解决方案是,小心地移除所有响应一个onunload事件的事件句柄

示例:具有IE兼容性的事件模型
定义了两个函数,Handler.add()和Handler.remove(),来从一个指定的元素增加和移除事件句柄。对支持addEventListener的平台,这些函数只是围绕标准方法的包围方法。在IE 5及其后的版本,例子定义了弥补不兼容问题的手段:
1 事件句柄被他们所注册的元素的方法调用
2 事件句柄被传递给一个模拟的事件对象,该对象尽可能地和DOM标准事件对象相匹配
3 事件句柄的重复注册被忽略
4 所有句柄都在文档卸载上注册,以防止IE中的内在泄漏
用于IE的一个事件兼容层:
var Handler = {};
if(document.addEventListener){
      Handler.add = function(element,eventType,handler){
            element.addEventListener(eventType,handler,false);
      }
      Handler.remove = function(element,eventType,handler){
            element.removeEventListener(eventType,handler,false);
      }
}
else if(document.attachEvent){
      Handler.add = function(element,eventType,handler){
            if(Handler._find(element,eventType,handler) != -1) return;
            //为了将句柄作为元素的方法调用,定义了嵌套函数并将其作为句柄函数注册
            var wrappedHandler = function(e){
                  if(!e)        e=window.event;
                  //创建模型事件对象
                  var event = {
                        _event:e,
                        type:e.type,
                        target:e.srcElement,
                        currentTarget:element,
                        relatedTarget:e.fromElement?e.fromElement:e.toElement,
                        eventPhase:(e.srcElement == element)?2:3,

                        clientX:e.clientX,clientY:e.clientY,
                        screenX:e.screenX,screenY:e.screenY,
                        
                        altKey:e.altKey,ctrlKey:e.ctrlKey,
                        shiftKey:e.shiftKey,charCode:e.keyCode,
                        stopPropagation:function(){this._event.cancelBubble = true;},
                        preventDefault:function(){this._event.returnValue = false;}
                  }
                  if(Function.prototype.call) handler.call(element,event);
                  else {
                           element._currentHandler = handler;
                           element._currentHandler(event);
                           element._currentHandler = null;
                  }
            };                     //wrappedHandler
            
            element.attachEvent("on"+eventType,wrappedHandler);
            //将这个句柄的所有信息存进一个对象
            var h = {
                        element:element,
                        eventType:eventType,
                        handler:handler,
                        wrappedHandler:wrappedHandler
            };
            //找出这个元素属于哪个文档,若它没有"document"属性,则它必定是document自身
            var d = element.document || element;
            var w = d.parentWindow;
            //我们必须将这个句柄与window联系起来,以便我们能在window卸载的时候移除
            var id = Handler._uid();
            if(!w._allHandlers) w._allHandlers = {};
            w._allHandlers[id] = h;
            
            if(!element._handlers) element._handlers = [];
            element._handlers.push(id);
            //若window未定义unload事件句柄,定义一个
            if(!w._onunloadHandlerRegistered){
                        w._onunloadHandlerRegistered = true;
                        w.attachEvent("onunload",Handler._removeAllHandlers);
            }
      };                              //Handler.add()
      Handler.remove = function(element,eventType,handler){
            var i = Handler._find(element,eventType,handler);
            if (i== -1) return;
            
            var d = element.document||element;
            var w = d.parentWindow;
            
            var handlerId = element._handlers[i];
            var h = w._allHandlers[handlerId];
            element.detachEvent("on"+eventType,h.wrappedHandler);
            //从数组中移除
            element._handlers.splice(i,1);
            delete w._allHandlers[handlerId];
      };
      Handler._find = function(element,eventType,handler){
            var handlers = element._handlers;
            if (!handlers) return -1;
            
            var d = element.document||element;
            var w = d.parentWindow;
            
            //我们从后往前找是因为最近注册的句柄最可能是要删除的
            for(var i= handlers.length-1;i>=0;i--){
                        var handlerId = handlers[i];
                        var h = w._allHanlders[handlerId];
                        if(h.eventType == eventType && h.handler == handler)  return i;
            }
            return -1;
      };
      
      Handler._removeAllHandlers = function(){
            //这个函数用attachEvent注册为onunload句柄,这意味着this引用事件发生的窗口对象
            var w = this;
            for(id in w._allHandlers){
                        var h = w._allHandlers[id];
                        h.element.detachEvent("on"+h.eventType,h.wrappedHandler);
                        delete w._allHandlers[id];
            }
      }
      Handler._counter = 0;
      Handler._uid = function(){return "h"+Handler._counter++;};
}
1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。
应用背景为变电站电力巡检,基于YOLO v4算法模型对常见电力巡检目标进行检测,并充分利用Ascend310提供的DVPP等硬件支持能力来完成流媒体的传输、处理等任务,并对系统性能做出一定的优化。.zip深度学习是机器学习的一个子领域,它基于人工神经网络的研究,特别是利用多层次的神经网络来进行学习和模式识别。深度学习模型能够学习数据的高层次特征,这些特征对于图像和语音识别、自然语言处理、医学图像分析等应用至关重要。以下是深度学习的一些关键概念和组成部分: 1. **神经网络(Neural Networks)**:深度学习的基础是人工神经网络,它是由多个层组成的网络结构,包括输入层、隐藏层和输出层。每个层由多个神经元组成,神经元之间通过权重连接。 2. **前馈神经网络(Feedforward Neural Networks)**:这是最常见的神经网络类型,信息从输入层流向隐藏层,最终到达输出层。 3. **卷积神经网络(Convolutional Neural Networks, CNNs)**:这种网络特别适合处理具有网格结构的数据,如图像。它们使用卷积层来提取图像的特征。 4. **循环神经网络(Recurrent Neural Networks, RNNs)**:这种网络能够处理序列数据,如时间序列或自然语言,因为它们具有记忆功能,能够捕捉数据中的时间依赖性。 5. **长短期记忆网络(Long Short-Term Memory, LSTM)**:LSTM 是一种特殊的 RNN,它能够学习长期依赖关系,非常适合复杂的序列预测任务。 6. **生成对抗网络(Generative Adversarial Networks, GANs)**:由两个网络组成,一个生成器和一个判别器,它们相互竞争,生成器生成数据,判别器评估数据的真实性。 7. **深度学习框架**:如 TensorFlow、Keras、PyTorch 等,这些框架提供了构建、训练和部署深度学习模型的工具和库。 8. **激活函数(Activation Functions)**:如 ReLU、Sigmoid、Tanh 等,它们在神经网络中用于添加非线性,使得网络能够学习复杂的函数。 9. **损失函数(Loss Functions)**:用于评估模型的预测与真实值之间的差异,常见的损失函数包括均方误差(MSE)、交叉熵(Cross-Entropy)等。 10. **优化算法(Optimization Algorithms)**:如梯度下降(Gradient Descent)、随机梯度下降(SGD)、Adam 等,用于更新网络权重,以最小化损失函数。 11. **正则化(Regularization)**:技术如 Dropout、L1/L2 正则化等,用于防止模型过拟合。 12. **迁移学习(Transfer Learning)**:利用在一个任务上训练好的模型来提高另一个相关任务的性能。 深度学习在许多领域都取得了显著的成就,但它也面临着一些挑战,如对大量数据的依赖、模型的解释性差、计算资源消耗大等。研究人员正在不断探索新的方法来解决这些问题
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值