js笔记4-事件基础

来源:互联网 发布:女装淘宝店铺简介 编辑:程序博客网 时间:2024/05/18 23:55

一个小小的点击事件例子:

document.onclick=function(){          alert('a');};

事件

事件的概念

事件:指的是文档或者浏览器窗口中发生的一些特定交互瞬间。我们可以通过侦听器(或者处理程序)来预定事件,以便事件发生的时候执行相应的代码。

事件对象

HTML DOM Event 对象
Event 对象代表事件的状态,比如事件在其中发生的元素、键盘按键的状态、鼠标的位置、鼠标按钮的状态。
事件通常与函数结合使用,函数不会在事件发生前被执行!

事件对象的获取

IE中事件是作为全局对象window.event存在的,而在Firefox中则是作为句柄(handler)的第一个参数传入内的。

事件的获取var evt=window.event||arguments[0];
第二种写法:function(ev){var e=ev||event;}

事件对象的应用
下面我们来讨论一下事件对象的实际运用。

事件处理程序

事件处理程序的概念

事件处理程序:我们用户在页面中进行的点击这个动作,鼠标移动的动作,网页页面加载完成的动作等,都可以称之为事件名称,即:click、mousemove、load等都是事件的名称。响应某个事件的函数则称为事件处理程序,或者叫做事件侦听器。

添加事件的两种方式

1.HTML事件处理程序
(1)直接在HTML元素行间属性里写JS代码
首先来举个栗子:
<div id="div1" onclick="alert('HTML事件')">DIV1</div>
这种直接在HTML元素行间属性里面写JS代码的方式,就是HTML事件处理的一种。
(2)定义一个函数,赋值给HTML元素的’on’+’xxx’属性
如下

 <div id="div2" onclick="show()">DIV2</div> <script type="text/javascript"> function show(){ alert('be clicked'); } </script>

HTML事件处理程序比较常用,但还有以下几个小小的缺点:

一、HTML代码与JavaScript代码耦合紧密,没有实现相互分离(而W3C标准是提倡结构、表现与行为的分离),进行代码的更新与维护的时候就需要改动两处,增加了工作量。
二、如果像第一个例子里那么写,代码的通用性差,会导致整站的代码量大。而如果提取出来,存放在函数当中,那么,会面临另一个问题——当函数还没有被解析,只是HTML、CSS代码加载完毕,用户进行点击,会完全没有反应,甚至引发错误。
三、扩展事件处理程序的作用域链在不同浏览器当中会导致不同的结果。
因此,我们需要一个更好的方式来对事件进行处理。

2.JavaScript事件处理程序
在JS中指定事件处理程序有三种方式、下面我们一一进行讨论:
(1)DOM0级事件处理程序
举个栗子:

 var oBtn=document.getElementById('btn1');//获取该按钮 oBtn.onclick=function(){//给按钮的点击事件绑定一个事件处理程序 alert(this.id+':I am clicked'); };

以这种方式添加的事件处理程序会在事件流的冒泡阶段被处理(当然,我们还没有说到事件流,这里先按下疑惑,下文中我们会讲到,暂时专心于事件的处理吧O(∩_∩)O)。

事件处理程序有添加,当然也该有删除,删除DOM0级事件处理程序的方法如下:
oBtn.onclick=null;//直接将该事件绑定的处理程序置空。

以该方式添加事件,IE6/7/8只支持window.event不支持参数传入,Firefox只支持参数传入不支持其它方式。IE9/Opera/Safari/Chrome 两种方式都支持。
这种方式虽然将JS于HTML完全分离了,但是也是一种比较早期的做法。而且也有一些不足之处:

一、每个事件只能绑定一个事件处理程序,如果绑定两次不同的事件处理程序,后绑定的会将前面绑定的处理程序置换。
二、只能在冒泡阶段被处理。

(2)DOM2级事件处理程序

DOM2级事件中定义了两个方法,用于处理指定和删除事件处理程序的操作:addEventListener()和removeEventListener()
所有DOM节点中都包含这两个方法,且它们都接受3个参数:要处理的事件名,做为事件处理程序的函数和一个布尔值。
最后这个参数如果是true,表示在捕获阶段调用事件处理程序;如果是fasle,表示在冒泡阶段调用事件处理程序。
同样举个栗子:

 var oBtn2=document.getElementById('btn2'); oBtn2.addEventListener('click',function(){ alert('clicked'); },false);

这种方式的有点在于可以同时添加多个事件处理程序,并且它们会按顺序在第一到n次事件触发时按照添加顺序一一执行。
但是上面这种写法有一个十分大的问题,思考一下,是什么问题呢?
是的,移除。addEventListener添加的事件处理程序只能使用removeEventListener来移除,但是当在添加事件时直接添加一个匿名函数,会导致移除无法成功。
要移除事件句柄,addEventListener()的执行函数必须使用外部函数,所以进行一下优化:

 var oBtn2=document.getElementById('btn2'); var show=function(){ alert('clicked); } oBtn2.addEventListener('click',show,false);

当然也可以这么写

 var oBtn2=document.getElementById('btn2'); function show(){ alert('clicked); } oBtn2.addEventListener('click',show,false);

不知你是否注意到了,在DOM2级中,我们添加的事件名是没有on的,在运用的时候,一定要牢牢记住~以防出现什么低级错误^ ^
最后,大多数情况下,事件的处理程序都被添加到事件流的冒泡阶段,所以第三个参数一般是false

该方法符合W3C标准,大部分浏览器都支持,但不支持低版本IE,IE9已支持。

(3)IE事件处理程序
IE中有与DOM2级类似的两个方法:attachEvent()和detachEvent().
这两个方法也接收两个相同的参数:要处理的事件名和作为事件处理程序的函数,由于IE只支持冒泡,所以通过IE方式添加的事件处理程序只会被添加到冒泡阶段。
再来一个栗子:)

var oBtn3=document.getElementById('btn3');oBtn3.addEvent('onclick',show);

同样的,attachEvent方法也能为元素添加多个事件处理程序,但是注意:事件触发时,这些函数的执行顺序与添加顺序完全相反
当然,为了能够移除成功,这里的事件处理程序依然不推荐使用匿名函数。

该方法在IE和Opear和谷歌中有效,不支持FF

为了同时兼容IE/FF和其他主流浏览器,使得每次code的时候可更方便,我们来写一个自己的方法。

function addEventHandler(obj,e,fn){    if(obj.attachEvent){    obj.attachEvent('on'+e,fn);    }    else{    obj.addEventListener(e,fn,false);    }}

来使用一下
addEventHandler(oBtn,'click',function(){alert('add success');});

事件流

概念

DOM(文档对象模型)结构是一个树型结构,当一个HTML元素产生一个事件时,该事件会在元素结点与根结点之间的路径传播,路径所经过的结点都会收到该事件,这个传播过程可称为DOM事件流。

DOM2级事件流”规定的事件流包括三个阶段:事件捕获阶段、处于目标阶段和冒泡阶段。首先发生的是事件捕获,为截获事件提供了机会。然后是实际的目标接收到事件。最后一个阶段是冒泡阶段,可以在这个阶段对事件作出响应。

两种事件模型

DOM同时支持两种事件模型:捕获型事件和冒泡型事件,但是,捕获型事件先发生。两种事件流会触发DOM中的所有对象,从document对象开始,也在document对象结束。

1.事件冒泡

IE的事件流叫做事件冒泡(event bubbling),事件开始时由最具体的元素(文档中嵌套层次最深的那个节点)(目标节点)接收,然后逐级向上传播到较为不具体的节点(文档)——根节点(document)。

当事件在某一DOM元素被触发,向父节点、祖先节点冒泡时,每遇到依附有该事件类型处理器的节点都会触发事件处理程序。

在冒泡过程中的任何时候都可以终止事件的冒泡,在遵从W3C标准的浏览器里可以通过调用事件对象上的stopPropagation()方法,在IE中可以通过设置事件对象的cancelBubble属性为true

如果不终止冒泡,事件将一直通过DOM冒泡直至到达文档根节点document.

2.事件捕获

事件捕获的思想是不太具体的节点应该更早的接收到事件,而最具体的节点应该在最后接收到节点。事件捕获的用意在于事件到达预定目标之前捕获它。

事件的处理将从DOM层次的根节点开始,从目标元素的所有祖先元素依次往下传递。在这个过程中,事件会被从文档根到事件目标元素之间各个继承派生的元素所捕获。

如果事件监听器在被注册时设置了useCapture属性为true,那么它们可以被分派给这期间的任何元素以对事件做出处理;否则,事件会被接着传递给派生元素路径上的下一元素,直至目标元素。

事件到达目标元素后,它会接着通过DOM节点再进行冒泡。

举个栗子
以简单的HTML页面为例,单击<div>元素会按照下图顺序触发事件
事件流

在DOM事件流中,实际的目标<div>元素在捕获阶段不会接收到事件。这意味着在捕获阶段,事件从document到<html>再到<body>后就停止了。下一个阶段是“处于目标”阶段,于是事件在<div>上发生,并在事件处理中被看成冒泡阶段的一部分。然后冒泡阶段发生,事件又传播回文档。

总结一下:事件冒泡和事件捕获:事件冒泡是由目标节点一直往父节点、祖先节点直到被终止,否则会一直冒泡到文档对象模型的根节点document;而事件捕获则完全相反,事件捕获由根节点开始,从所有祖先元素一直往下传递到具体的目标节点。

兼容性:

Safari、Chrome、Firefox和Opera9.5及更高版本都会在捕获阶段触发事件对象上的事件。即:在这些浏览器中,有两次机会可以在目标对象上操作事件。
Opera、Firefox、Chrome和Safari都支持DOM事件流;IE不支持DOM事件流、只支持事件冒泡。
在DOM中,文本节点也触发事件、而IE中则不会


事件类型

事件类型有:
1.window事件
onload-完成加载
onunload-用户退出页面
onresize-窗口或框架被重新调整大小
onselect-文本被选中
onscroll-滚动带滚动条的元素中的内容
onabort-图像加载被中断

2.鼠标事件
onclick-对象被点击
ondbclick-双击
onmousedown-鼠标按键被按下
onmousemove-鼠标被移动
onmouseup-鼠标按键被松开
onmouseover-鼠标移到某元素之上
onmouseout-鼠标从某元素移开
oncontextmenu-鼠标点击右键
onmousewheel-鼠标滚轮

3.键盘事件
onkeydown-某键盘按键被按下
onkeyup-某键盘按键被松开
onkeypress-某键盘按键被按下并松开

4.表单事件
onsubmit-表单被提交
onreset-表单被重置
onchange-域中内容被修改
onfocus-元素获得焦点
onblur-元素失去焦点
oninput-输入

默认行为

什么是默认行为:
我的理解是:事件发生时浏览器默认的处理程序
阻止默认行为-阻止默认事件
普通写法return false;//既阻止了冒泡,也阻止了默认行为
-例1:阻止默认右键菜单

document.oncontextmenu=function(){  return false;};

-例2.只能输入字母的输入框

    var oTxt=document.getElementById('txt1');        oTxt.onkeydown=function(ev){            var e=ev||event;        if((e.keyCode>90||e.keyCode<65)&&e.keyCode!=8){                return false;            }        };

最后是一个实践-
磁性吸附

<!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8">    <title>拖拽-磁性吸附</title>    <style type="text/css">    *{margin:0;padding: 0;}    #div1{        width: 100px;        height: 100px;        background: red;        position: absolute;    }    </style>    <script type="text/javascript">        window.onload=function(){            var oDiv=document.getElementById('div1');            oDiv.onmousedown=function(ev){                var e=ev||event;                var disX=e.clientX-oDiv.offsetLeft;                var disY=e.clientY-oDiv.offsetTop;                document.onmousemove=function(ev){                    var e=ev||event;                    var l=e.clientX-disX;                    var t=e.clientY-disY;                    if (l<50) {                        l=0;                    }                    if (l>document.documentElement.clientWidth-oDiv.offsetWidth-50) {                        l=document.documentElement.clientWidth-oDiv.offsetWidth;                    }                    if (t<50) {                        t=0;                    }                    if (t>document.documentElement.clientHeight-oDiv.offsetHeight-50) {                        t=document.documentElement.clientHeight-oDiv.offsetHeight;                    }                    oDiv.style.left=l+'px';                    oDiv.style.top=t+'px';                };                document.onmouseup=function(){                document.onmousemove='';                document.onmouseup='';                };                return false;            };        }    </script></head><body>    <div id="div1"></div></body></html>
0 0
原创粉丝点击