Javascript事件机制

JavaScript与HTML之间的交互是通过事件实现的。事件就是文档或浏览器窗口中发生的一些特定的交互瞬间。

事件的组成

事件源 事件类型 事件处理程序 我们也称为事件三要素

  1. 事件源:事件被触发的对象 例如按钮对象
  2. 事件类型:如何触发例如鼠标单击选中、键盘按下 
  3. 事件处理程序:通过一个函数赋值的方式
<button onclick="console.log('Clicked')">点我啊</button>
//button:事件源  单击鼠标:事件类型 console.log....:事件处理程序

常用事件:

用户点击鼠标时

网页加载后

图像加载后

鼠标悬浮时...

执行事件的步骤

  1. 获取事件源
  2. 注册事件(绑定事件)
  3. 采用函数赋值形式添加事件处理程序

1.事件流

事件流描述了页面接收事件的顺序。IE 将支持事件冒泡流,而 Netscape Communicator 将支持事件捕获流。

1.1 事件冒泡(IE事件流)

IE 事件流被称为事件冒泡,这是因为事件被定义为从最具体的元素(文档树中最深的节点)开始触发,然后向上传播至没有那么具体的元素(文档)。

例如:

 <div id="outer">outer
    <div id="center">center
      <div id="inner">inner</div>
    </div>
  </div>
  <script>
    var inner = document.getElementById('inner');
    var center = document.getElementById('center');
    var outer = document.getElementById('outer');
    // 当我们只有一个inner点击方法的时候 我们发现想要实现的效果和我们预期的一样
    inner.onclick = function () {
      console.log('我是inner点击的');
    }
    // 但是当我们给inner的父元素和祖先元素也添加点击事件时 一点击inner 所有祖先元素的事件都会被触发,这就是事件冒泡现象
    center.onclick = function () {
      console.log('我是center点击的');
    }
    outer.onclick = function () {
      console.log('我是outer点击的');
    }
  </script>

在点击页面中的id为inner的div元素,click事件会以如下顺序发生

div#inner- > div#center -> div#outer -> body -> html -> document

 

所有现代浏览器都支持事件冒泡,只是在实现方式上会有一些变化。IE5.5及早期版本会跳过html元素(从body直接到 document)。现代浏览器中的事件会一直冒泡到 window 对象。

阻止事件冒泡

event.stopPropagation()

Event对象代表事件的状态,比如事件在其中发生的元素、键盘按键的状态、鼠标的位置、鼠标按钮的状态。

事件通常与函数结合使用,函数不会在事件发生前被执行!只想当前事件被执行,外层的绑定的事件不被执行,直接在对应方法中使用event.stopPropagation()阻止事件冒泡

<div id="outer">outer
  <div id="center">center
    <div id="inner">inner</div>
  </div>
</div>
<script>
  var inner = document.getElementById('inner');
  var center = document.getElementById('center');
  var outer = document.getElementById('outer');
  // 当我们只有一个inner点击方法的时候 我们发现想要实现的效果和我们预期的一样
  inner.onclick = function () {
    console.log('我是inner点击的');
  }
  // 但是当我们给inner的父元素和祖先元素也添加点击事件时 点击inner 所有祖先元素的事件都会被触发,这就是事件冒泡现象
  center.onclick = function () {
  //阻止事件冒泡
    event.stopPropagation();
    console.log('我是center点击的');
  }
  outer.onclick = function () {
    event.stopPropagation();
    console.log('我是outer点击的');
  }
</script>

注意:如果点击方法时需要同时传递其他参数和event,直接传递event这个单词即可

οnclick="test(123,event)"

1.2.事件捕获(Netscape事件流)

事件捕获的意思是最不具体的节点应该最先收到事件,而最具体的节点应该最后收到事件。事件捕获实际上是为了在事件到达最终目标前拦截事件。

如果前面的例子使用事件捕获,则点击div元素会以下列顺序触发 click 事件:

document ->html -> body -> div#outer - > div#center -> div#inner

在事件捕获中,click 事件首先由 document 元素捕获,然后沿 DOM 树依次向下传播,直至到达实际的目标元素div。

                               

1.3.DOM事件流

DOM2 Events 规范规定事件流分为 3 个阶段:事件捕获、到达目标和事件冒泡。事件捕获最先发生,为提前拦截事件提供了可能。然后,实际的目标元素接收到事件。最后一个阶段是冒泡,最迟要在这个阶段响应事件。

 

捕获阶段从document 到html再到body就结束了。下一阶段,即会在div元素上触发事件的“到达目标”阶段,通常在事件处理时被认为是冒泡阶段的一部分。冒泡阶段,事件反向传播至文档。虽然 DOM2 Events 规范明确捕获阶段不命中事件目标,但现代浏览器都会在捕获阶段在事件目标上触发事件。最终结果是在事件目标上有两个机会来处理事件。

注意:所有现代浏览器都支持 DOM 事件流,只有 IE8及更早版本不支持。

2.事件处理程序

为响应事件而调用的函数被称为事件处理程序(或事件监听器)。事件处理程序的名字以"on"开头,例如:onclick、onload。

2.1.HTML 事件处理程序

特定元素支持的每个事件(单击click、加载load等),都可以使用事件处理程序的名字以 HTML 属性的形式来指定。此时属性的值必须是能够执行的 JavaScript 代码。

<!-- 这里的this相当于事件的目标元素 -->
<button onclick="this.innerHTML = '我被改变了'">点我</button>

<button onclick="console.log('Clicked')">点我</button>
<!-- js语句 当语句里用了双引号那么外面只能用单引号,反之亦然 -->
<!-- 如果确实需要使用双引号可以写成如下形式 -->
<button onclick="console.log(&quot;Clicked&quot;)">点我</button>

在 HTML 中定义的事件处理程序也可以调用页面其他地方定义的方法。

<!-- 执行函数需要加() -->
<button onclick="tig()">点我</button>
<script>
  function tig() {
    console.log('Hello Wolrd');
  }
</script>

 2.2.DOM0 事件处理程序

<button id='btn'>点我啊</button>
<script>
  <!-- 获得按钮 -->
  var btn = document.getElementById('btn');
  <!-- 给按钮的onclick事件处理程序赋值(这个值为一个函数) -->
  btn.onclick = function () {
    console.log('我被点击了');
  }
</script>

前面的代码在运行之后才会给事件处理程序赋值。因此如果在页面中上面的代码出现在按钮之后,则有可能出现用户点击按钮却没有反应的情况。

像这样使用 DOM0 方式为事件处理程序赋值时,所赋值的函数被视为元素的方法。因此,事件处理程序会在元素的作用域中运行。下面的例子演示了使用 this 引用元素本身:

<button id='btn'>点我</button>
<script>
  var btn = document.getElementById('btn');
  btn.onclick = function () {
    console.log('点了');
    console.log(this.id); //btn button元素的方法this指向button
  }
</script>

以这种方式添加事件处理程序是注册在事件流的冒泡阶段的。

移除通过DOM0方式添加的事件处理程序

<button id='btn'>点我</button>
<script>
  var btn = document.getElementById('btn');
  btn.onclick = function () {
    console.log('点了');
    console.log(this.id); //btn button元素的方法this指向button
    btn.onclick = null; // 移除通过DOM0方式添加的事件处理程序
    //这里也可以写成 this.onclick = null
  }
</script>

2.3.DOM2 事件处理程序

DOM2 Events 为事件处理程序的赋值和移除定义了两个方法:addEventListener()和removeEventListener()

addEventListener()

添加事件处理  addEventListener(事件名,事件处理函数, 布尔值);

<button id='btn'>点我</button>
<script>
  var btn = document.getElementById("btn");
  btn.addEventListener("click", function () {
    console.log('点了');
  }, false);
</script>
<!-- true表示在捕获阶段调用事件处理程序,false(默认值)表示在冒泡阶段调用事件处理程序 -->

与 DOM0方式类似,这个事件处理程序同样在被附加到的元素的作用域中运行。DOM2方式的主要优势是可以为同一个事件添加多个事件处理程序。多个事件处理程序以添加顺序来触发。

  <button id="btn">点我</button>
  <script>
    //获取button的引用
    var btn = document.getElementById('btn')  
    //添加第一个事件处理程序
    btn.addEventListener('click', function (event) {
      console.log(event);
      console.log('按钮一被点击了');
    })
    // btn.addEventListener('click', function () {
    //   console.log(this.id);
    // })  作用域与DOM0方式类似
    //添加第二个事件处理程序
    var handler = function () {
      console.log('我是一个handler方法');
    }
    btn.addEventListener('click', handler)
  </script>

removeEventListener()

通过 addEventListener()添加的事件处理程序只能使用 removeEventListener()移除。这意味着使用 addEventListener()添加的匿名函数无法移除

  <button id="btn">点我</button>
  <script>
    //获取button的引用
    var btn = document.getElementById('btn')  
    //添加第一个事件处理程序
    btn.addEventListener('click', function (event) {
      console.log('点了');
    })
    // btn.addEventListener('click', function () {
    //   console.log(this.id);
    // })  作用域与DOM0方式类似
    //添加第二个事件处理程序
    var handler = function () {
      console.log('我是一个handler方法');
    }
    btn.addEventListener('click', handler)
    //移除通过addEventListener()添加的事件处理程序
    //传入的参数为要删除的函数名 运行后发现点击按钮只有第二个事件处理程序被移除了
  </script>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值