js中DOM事宜探讨

事宜

纲领

  1. 明白事宜流

  2. 应用事宜处置惩罚递次

  3. 差别的事宜范例

javascript和html的交互是经由过程事宜完成的。事宜就是文档或浏览器窗口发作的一些特定交互霎时。可以应用侦听器(事宜处置惩罚递次)预定事宜,以便事宜发作时实行相应的代码。

1 事宜流

浏览器发展到第四代时(IE4和Netscape communicator4)都以为,当你单击某个按钮时,在单击这个按钮的同时,你也单击了包含这个按钮的容器以至悉数页面。就犹如你用手指指向一同心圆的圆心,你指向的不单是一个圆,而是以这个圆心为圆心的一切圆。
所谓事宜流,指的是页面吸收事宜时的递次。IE提出的事宜流是事宜冒泡流,Netscape communicator提出的事宜流是事宜捕捉流。

1.1 事宜冒泡流

事宜开始时,由最细致的元素(文档中嵌套条理最深的哪一个节点)吸收,逐级上传到最不细致的元素(文档)。

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title></title>
  </head>
<body>
  <div id='myDiv'>click me</div>
</body>
</html>

上段代码,依据冒泡流的说法,就是你点击div时,沿着DOM树,你也点击了body,html,document。

1.2 事宜捕捉流

吸收事宜的递次,由不太细致的节点先吸收,逐级向下传到细致的节点。其意图就是在事宜抵达目的之前先捕捉他。

1.3 DOM事宜流

‘DOM2级事宜’,划定事宜流包含三个阶段。事宜捕捉阶段、处于目的阶段、事宜冒泡阶段。在事宜冒泡阶段对事宜做出相应。单击<div>元素会按下图所示递次触发事宜

《js中DOM事宜探讨》

在DOM事宜流中,现实的目的(<div>元素)在捕捉阶段不会吸收到事宜,这意味着在捕捉阶段,事宜从document到<html>再到<body>就住手了。下一个阶段是’处于目的‘阶段,因而事宜在<div>上发作,并在事宜处置惩罚中被算作是冒泡阶段的一部份,然后冒泡阶段发作,事宜又流传回文档。

多半支撑DOM事宜流的浏览器都完成了一种特定的行动:纵然”DOM2级事宜”范例明确要求捕捉阶段不会触及事宜目的,但IE9、Safari、Chrome、Firefox和Opera9.5及更高版本都邑在捕捉阶段触发事宜对象上的事宜。效果,就有两个时机在目的对象上面操纵事宜。(注重,IE8及更早版本不支撑DOM事宜流)

  1. 下面这段递次,可以看出在捕捉阶段(时机1)和冒泡阶段(时机2)都在目的对象上操纵(触发)了事宜

  2. 运转这段递次,离别点击红黄绿地区,感觉下DOM事宜实行的递次:(在DOM2级事宜处置惩罚递次中,绑定在目的元素上的事宜实行递次是按事宜的注册先后递次实行的,所以alert3.2在3.1之前。)

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title></title>
  </head>
<body>
    <div id="box" style="background:red;width:200px;height:200px;">
        <div id="outer" style="background:yellow;width:150px;height:150px;">
            <div id="inner" style="background:green;width:70px;height:70px;">click me</div>
        </div>
    </div>
  <script type="text/javascript">
window.onload=function(){
    var Box=document.getElementById('box');
    var outer = document.getElementById("outer");
    var inner = document.getElementById('inner');
    //true为事宜捕捉,false为事宜冒泡
    Box.addEventListener("click",function(){
        alert('1');
    },true)

    Box.addEventListener("click",function(){
        alert('4');
    },false)

    outer.addEventListener("click", function(){
      alert("2");
    }, true);

    inner.addEventListener("click",function(){
        alert('3.2')
    },false);

    inner.addEventListener("click", function(){
      alert("3.1");
     }, true);
    
}
  </script>
</body>
</html>

2 事宜处置惩罚递次

事宜就是用户或浏览器自身实行的某种行动。如click,load,mouseover等都是事宜的名字。而相应某个事宜的函数叫事宜处置惩罚递次。事宜处置惩罚递次的名字以”on”开首,因而click事宜的事宜处置惩罚递次就是onclick。为事宜指定处置惩罚递次的体式格局有好几种。

2.1 HTML事宜处置惩罚递次

某个元素支撑的每种事宜,都可以应用一个与之相应 事宜处置惩罚递次 同名的 HTML 特征(属性)来指定。这个特征的值应该是能实行的Javascript代码。比方,要在按钮被单击时实行一些Javascript:<input type=”button” value=”Click me” onclick=”alert(‘hello world’)”/>。

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title></title>
  </head>
<body>
  <script type="text/javascript">
    function showMessage(){
      alert('hello world');
    }
  </script>
    <div id="box">
        <input type="button" value="Click me" onclick="showMessage()"/>
    </div>
</body>
</html>

在HTML中指定事宜处置惩罚递次有两个瑕玷

  • 瑕玷一 时间差,HTML加载完成,但js还未加载完成(平常状况,HTML是按注册递次加载的),假如在showMessage()函数剖析前就单击事宜,便会激发毛病。

解决办法:将HTML事宜处置惩罚递次封装在一个try-catch块中

<input type="button" value="Click me" onclick="try{showMessage();}catch(ex){}"/>

/番外篇/

try…catch 的作用是测试代码中的毛病。

语法:

try
{
   //在此运转代码
   tryStatements
}
catch(err)
{
   //在此处置惩罚毛病
  catchStatements 
}

参数:

tryStatements 必选项,可以发作毛病的代码
catchStatements 可选项,发作tryStatements中关联的毛病后实行的代码

示例一,请点击肯定/作废

<html>
<head>
<script type="text/javascript">
var txt=""
function message()
{
try
  {
    //准确是 alert,毛病代码即 adddlert
  adddlert("Welcome guest!")
  }
catch(err)
  {
  txt="There was an error on this page.\n\n"
  txt+="Click OK to continue viewing this page,\n"
  txt+="or Cancel to return to the home page.\n\n"
  //confirm(message)---要在 window 上弹出的对话框中显现的纯文本(而非 HTML 文本)
  if(!confirm(txt))
    {
    document.location.href="https://segmentfault.com/u/xiakejie"
    }
  }
}
</script>
</head>
<body>
<input type="button" value="View message" onclick="try{message();}catch(err){}" />
</body>
</html>

语法:

try  {  
   tryStatements}  
catch(exception){  
   catchStatements}  
finally  {  
   finallyStatements}

参数:
finallyStatements:可选项,当tryStatements,catchStatements皆抛出毛病实行的代码

示例二 与稍后讲的跨浏览器处置惩罚递次比较,与if…elaeif…else比较(对这里的要领若不明白,背面会讲到)

<html>
<head>
</head>
<body>
<input id='b1' type='button' value='按钮'/>
<script>
(function(){
  var oBtn=document.getElementById("b1");
  function mto(){
  alert("123");
  };

  try 
  {
  oBtn.attachEvent("onclick",mto);
  }
  catch(e)
  {
  oBtn.addEventListener("click",mto,false);
  }
  finally //DOM0级事宜处置惩罚递次  
  {  
  oBtn.onclick=mto;
   }

 })();
</script>
</body>
</html>

  • 瑕玷二 HTML与javascript代码严密耦合,假如要替换事宜处置惩罚递次,HTML部份和javascript部份都要修正。(别的一个瑕玷会在后续另篇文章剖析)

2.2 DOM0级事宜处置惩罚递次

经由过程Javascript指定事宜处置惩罚递次的传统体式格局,就是将一个函数赋值给一个事宜处置惩罚递次属性。这类为事宜处置惩罚递次赋值的要领,在第四代WEB浏览器涌现,至今一切的浏览器都支撑。要应用javascript指定事宜处置惩罚递次,起首必需取得一个要操纵的对象的援用

每一个元素(包含window document)都有自身的事宜处置惩罚递次属性,这些属性一般悉数小写,比方onclick。以下

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title></title>
  </head>
<body>
  <div id="box">
      <input type="button" value="Click me" id="btn" />
  </div>
  <script type="text/javascript">
    function showMessage(){
      alert('DOM0级事宜处置惩罚递次');
    }
    var oBtn=document.getElementById('btn');
    oBtn.onclick=showMessage;
  </script>
</body>
</html>

在此我们经由过程一个文档对象取得一个按钮的援用,然后为他指定了onclick事宜处置惩罚递次,但要注重在这些代码(比方这里的showmessage函数代码)运转之前不会指定事宜处置惩罚递次(指的是当你点击按钮时,不会实行showmessage函数代码,因为这些代码有可以还没有运转),因而假如这些代码在页面中位于按钮背面,有可以在一段时间内怎样点击都没有回响反映。

2.2.1 番外篇

许多同砚也许疑惑 oBtn.onclick=showMessage;oBtn.onclick=showMessage(); 区分

showMessage是一个函数名,ECMAscript中函数是一个对象,函数名则是一个指向函数对象的指针,应用不带括号的函数名是接见函数指针,而不是挪用函数。若要挪用则带括号。

我是如许明白的 var funName=function(){...}; 是一个函数表达式,这个函数表达式是将一个匿名函数赋值给一个变量。在JS是面向对象编程言语,变量也是对象。

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title></title>
  </head>
<body>
  <script type="text/javascript">
    var fnName=function(){
    alert('Hello World');
    }();
  </script>
</body>
</html>

上例我们看出函数表达式后加()直接挪用。如许明白 var funName=function(){...}; 就是一个函数表达式,oBtn.onclick=showMessage(); 如许就是把他算作一个函数表达式,而且直接实行这个函数,而不是DOM0级事宜处置惩罚递次。这块学问我在另一篇文章中有细致解说 https://segmentfault.com/a/11…

2.2.2 DOM0级事宜处置惩罚递次的作用域

应用DOM0级要领指定事宜处置惩罚递次被以为是元素的要领(之所以称元素的要领,是因为应用DOM0级事宜处置惩罚递次必需起首取得一个操纵对象,这个操纵对象也就是DOM元素)。因而这时候事宜处置惩罚递次是在元素的作用域中举行。那末,递次中的this援用当前元素。在事宜处置惩罚递次中可以经由过程this接见元素的任何属性和要领。DOM0级事宜处置惩罚递次会在事宜流的冒泡阶段被处置惩罚。

var oBtn=document.getElementById('btn');
oBtn.onclick=function(){
    alert(this.id)
};

2.2.3 删除DOM0级事宜处置惩罚递次

oBtn.onclick=null;

2.3 DOM2级事宜处置惩罚递次

DOM2级事宜处置惩罚递次定义了两个要领:用于处置惩罚指定和删除事宜处置惩罚递次的操纵,addEventListener()和removeEventListener()。一切的DOM节点都包含这两个要领。都吸收三个参数:要处置惩罚的事宜名,作为事宜处置惩罚递次的函数和布尔值。true示意在捕捉阶段挪用事宜处置惩罚递次,false示意在冒泡阶段挪用事宜处置惩罚递次。应用DOM2级要领指定事宜处置惩罚递次也被以为是元素的要领,事宜处置惩罚递次也是在元素的作用域中运转的,也可以经由过程this接见元素的任何属性和要领。

2.3.1 DOM2级事宜处置惩罚递次长处

可以增加多个事宜处置惩罚递次。而且按增加的递次触发。

var oBtn=docunment.getElementById('myBtn');
oBtn.addEventListener('click',function(){alert(this.id)},false);
oBtn.addEventListener('click',function(){alert('hello')},false);

2.3.1 DOM2级事宜处置惩罚递次的移除

经由过程addEventListener()增加的事宜处置惩罚递次只能用removeEventListener()移除,而且传入参数要与增加处置惩罚递次参数完全雷同。意味着经由过程abbEventListener()增加的匿名函数没法被移除

为了兼容种种浏览器我们大多半将事宜处置惩罚递次增加到事宜流的冒泡阶段。除非为了在事宜抵达目的前捕捉他,才将事宜处置惩罚递次增加到捕捉阶段。

2.3.2 支撑的浏览器

IE9,Firefox,Safari,Chrome和Opers支撑DOM2级事宜处置惩罚递次。

2.4 IE事宜处置惩罚递次

IE事宜处置惩罚递次,指定和删除事宜处置惩罚递次要领:attachEvent()和detachEvent().接收雷同的两个参数,事宜处置惩罚递次称号与事宜处置惩罚递次函数,(注重DOM2级第一个参数是事宜名)。经由过程attachEvent()增加的事宜处置惩罚递次都邑被加到冒泡阶段,是因为IE8及更早版本只支撑冒泡事宜流

应用attachEvent()为按钮增加一个事宜处置惩罚递次.

var bnt = document.getElementById('bnt');
btn.attachEvent('onclick',function(){alert("hello");});

IE事宜处置惩罚递次与DOM0级事宜处置惩罚递次重要区分:事宜处置惩罚递次的作用域。应用DOM0级要领,事宜处置惩罚递次是在其所属元素内运转;attachElent()要领时,事宜处置惩罚递次是在全局作用域中运转,this值因而即是Window. 在编写跨浏览器代码时切记这一区分(跨浏览器稍后会说到)

同DOM2级事宜处置惩罚递次一样,移除事宜只能经由过程detachEvent()移除,而且传入的参数要一样。

2.4.1支撑的浏览器

IE和Opera

2.5跨浏览器事宜处置惩罚递次

回忆一下前面的几种事宜处置惩罚递次。HTML事宜处置惩罚递次,DOM0级事宜处置惩罚递次,DOM2级事宜处置惩罚递次,IE事宜处置惩罚递次。

HTML事宜处置惩罚递次,合适一切浏览器;DOM0级,合适一切浏览器;DOM2级,合适IE9,Firefox,Safari,Chrome和Opers;IE事宜处置惩罚递次,合适IE和Opera。

2.5.1 跨浏览器事宜处置惩罚递次

为了以跨浏览器体式格局处置惩罚事宜,要领一,应用可以断绝浏览器差别的javascript库。要领二,自身开辟最合适的处置惩罚要领。我们这里应用的就是要领二。应用才能检测头脑。我们要保证处置惩罚事宜的代码在大多半浏览器下一致的运转,只需关注冒泡阶段(因为一切当代浏览器都支撑事宜冒泡)。

在讲跨浏览器事宜处置惩罚递次之前,我们先复习一下Object。建立Object实例的体式格局有两种

  • 应用NEW操纵符后跟Object实例,var person = new Object(); person.name="liMing"; person.age = 29;

  • 第二种是应用对象字面量示意法,var person = {name:"liMing",age:29};

接见对象属性要领也有两种

  • 点示意法。alert(person.name);

  • 第二种是是方括号示意法,alert(person['name']);//长处,可以经由过程变量来接见属性

建立一个对象eventUtil,对象包含两个要领,一个要领给元素增加事宜addHeadler(),另一个要领给元素去除事宜removeHeader()。要领接收三个参数,要操纵的元素,事宜称号,和事宜处置惩罚递次函数。

var EventUtil = {
  addHandler : function (element,type,handler){
    if (element.addEventListener) {
      element.addEventListener(type,handler,false);
    }else if (element.attachEvent) {
      element.attachEvent('on'+type,handler);
    }else {
      element['on'+type]=handler;
    }
  },
  removeHandler : function(element.type,handler){
    if (element.removeEventListener) {
      element.addEventListener(type,handler,false);
    }else if (element.attachEvent) {
      element.attachEvent('on'+type,handler);
    }else {
      element['on'+type]=null;
    }
  } 
};

援用:EventUnit.addHandler(element,'click',handler);

简析:可以将EventUnil算作应用对象字面量法建立的Object实例。addHandler,removeHandler算作对象的属性。在ECMAScript中函数名自身就是变量,所以函数也可以作为值来应用,所以可以讲function(evement,type,handler){}看做是属性的值。因为ECMAScript中函数可以传进来多个参数,参数的数据范例不限定,所以这里可以传入对象eventment,字符串type,函数/对象handler.

援用情势的简析:
建立一个对象:var person = {name:’liMing’}; 也可以var person=new Object(); person.name=’liMing’;
那末EventUnil.addHandler(element,’click’,handler)可以明白为var EventUnil.addHandler=function(){};这一函数表达式的挪用。注,以上简析均是个人明白,若不准确,愿望斧正。

3 事宜对象

在触发DOM上的某个事宜时,会发生一个事宜对象Event,这个对象包含着一切与事宜有关的信息。一切的浏览器都支撑Event对象,但支撑的体式格局差别。

3.1 DOM中的事宜对象

不管指定事宜处置惩罚递次时应用什么要领(DOM0,DOM2),都邑传入Event对象。event对象包含与建立它的特定事宜有关的属性和要领,触发的事宜范例不一样,可用的属性和要领也不一样,不过,一切事宜都邑有下表列出的成员

《js中DOM事宜探讨》
《js中DOM事宜探讨》

3.1.1 currentTarget 与 target

在事宜处置惩罚递次内部,对象this一直即是currentTarget的值,而target则只包含事宜的现实目的。事宜处置惩罚递次存在于按钮的父节点中(比方document.body)

document.body.onclick=function(event){
  alert(event.currentTarget===document.body);//true
  alert(this===document.body);//true
  alert(event.target===document.getElementById('myBtn')); //true
}

该效果是因为按钮上没有注册事宜处置惩罚递次,点击按钮时,click事宜冒泡到了document.body,在那里事宜才获得处置惩罚。

3.1.2 type

在须要一个函数处置惩罚多个事宜时,可应用type属性

var btn = document.getElementById('myBtn');
var handler = function(event){
  switch (event.type){
    case 'click';
    alert('clicked');
    break;

    case 'mouseover';
    event.target.style.backgroundColor = 'red';
    break;

    case 'mouseout';
    event.target.style.backgroundColor = '';
    break;
  }
};
btn.click = handler;
btn.mouseover = handler;
btn.mouseout = handler;

3.1.3 阻挠事宜的默许行动 preventDefault()

作废特定事宜的默许行动。比方,链接的默许行动就是在被单击时会导航到href特征指定的URL,假如你想阻挠链接导航这一默许行动,经由过程链接的onclick事宜处置惩罚递次作废它。

var link = document.getElementById('myLink');
link.onclick = function(event){
    event.preventDefault();
};

3.1.4 作废进一步事宜的捕捉或冒泡 stopPropagation()

在讲currentTarget与target时,我们晓得按钮没有注册事宜处置惩罚递次,click事宜冒泡到了document,body上。如今我们可以阻挠冒泡行动了,效果防止触发注册在document.body上的事宜处置惩罚递次

  var btn = document.getElementById('myBtn');
  btn.onclick = function(event){
    event.stopPropagation();
  };
  document.body.onclick = function(event){
    alert(event.currentTarget===document.body);
    alert(this===document.body);
    alert(event.target===btn);
  };
  

3.1.5 肯定事宜位于当前事宜流谁人阶段eventPhase

注重,只要在事宜处置惩罚递次实行时期,event对象才会存在,一旦事宜处置惩罚递次实行终了,event对象便会被烧毁。

3.2 IE中的事宜对象

要接见IE中的event对象有几种差别的体式格局,接见的体式格局取决于指定事宜处置惩罚递次的要领。

  • 应用DOM0级要领增加事宜处置惩罚递次。event对象作为window对象的一个属性存在。

var btn = document,getElementById('myBtn');
btn.onclick = function(){
    var event = window.event;
    alert(event.type); //"click"
};
  • 应用IE要领增加事宜处置惩罚递次,event对象作为参数传入事宜处置惩罚递次中。

var btn = document,getElementById('myBtn');
btn.attachEvent ("onclick",function(event){
  alert(event.type);//"click"
});
  • 经由过程HTML特征指定事宜处置惩罚递次,经由过程一个名为event变量接见event对象(与DOM中的事宜模子雷同)

<input type="button" value="click me" onclick="alert(event.type)"/>

3.2.1 IE中event对象的属性和要领

个中许多属性和要领都有对应的或相干的DOM属性和要领,与DOM的event对象一样,这些属性和要领也会因为事宜范例的差别而差别,但一切事宜对象都邑包含下表所列的属性和要领
《js中DOM事宜探讨》

3.2.2 事宜目的
因为事宜处置惩罚递次作用域是依据指定他的体式格局肯定的,所以不能以为this一直即是事宜目的。因为我的浏览器版本题目,书中的征象复现不了,所以用下递次替代。

  var btn = document.getElementById('myBtn');
  function showMes(event){
    var event = window.event||event;
    var ele = event.target||event.srcElement;
    alert(ele === this);
  };
  var eventUnit = {
    addHandler: function(element,type,handler){
      if (element.attachEvent) {
        element.attachEvent(type,handler)
      }else{
        element[type]=handler;
      }
    }
  };
  eventUnit.addHandler(btn,'onclick',showMes);

3.2.3 作废事宜的默许行动,returnValue

returnValue属性相称与DOM中的preventDefault()要领,只要将returnValue设置为falsae就可以阻挠事宜的默许行动。一样因为浏览器版本题目,书中代码修正以下:

  var link = document.getElementById('myLink');
  function stopEvent(event){
    var event = event||window.event;
    event.returnValue = false;
    event.preventDefault();
  };
  link.onclick = stopEvent;

3.2.4 阻挠事宜冒泡 cancelBubble

cancelBubble属性与DOM中的stopPropagatioin()要领作用雷同,IE不支撑事宜捕捉,所以只用作废事宜冒泡。事宜处置惩罚递次中将cancelBubble设置为true便可以阻挠事宜冒泡行动。

3.3 跨浏览器的事宜对象

<body>
  <input type="button" name="button" id="myBtn" value="button">
  <a href="http://www.w3school.com.cn" id="myLink">W3School</a>
  <script type="text/javascript">
  var btn = document.getElementById('myBtn');
  var link = document.getElementById('myLink');
  var EventUtil = {
    getEvent : function(event){
      return event?event:window.event;
    },
    getTarget : function(event){
      return event.target||event.srcElement;
     //return event.target?event.target:event.srcElement;
    },
    preventDefault : function(event){
      if (event.preventDefault) {
        event.preventDefault();
      }else{
        event.returnValue = false;
      }
    },
    stopPropagation : function(event){
      if (event.stopPropagation) {
        event.stopPropagation();
      }else{
        event.cancelBubble = true;
      }
    },
  };
  btn.onclick = function(event){
    event = EventUtil.getEvent(event);
  };
  link.onclick = function(event){
    event = EventUtil.getEvent(event);
    EventUtil.preventDefault(event);
    EventUtil.stopPropagation(event);
  };
  btn.onclick = function (event){
    event=EventUtil.getEvent(event);
    target = EventUtil.getTarget(event);
    alert('stopPropagation');
    alert(target);
    EventUtil.stopPropagation(event);
  };
  document.body.onclick = function(event){
    alert('body clicked');
  };
  </script>
</body>

本文参考javascript高等递次设计第三版

    原文作者:下客介
    原文地址: https://segmentfault.com/a/1190000008942717
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞