a标签点击事件_DOM事件机制

前言

本文主要介绍DOM事件级别、DOM事件模型、事件流、事件代理和Event对象常见的应用,希望对你们有些帮助和启发!

一、DOM事件级别

DOM级别一共可以分为四个级别:DOM0级、DOM1级、DOM2级和DOM3级。而DOM事件分为3个级别:DOM 0级事件处理,DOM 2级事件处理和DOM 3级事件处理。由于DOM 1级中没有事件的相关内容,所以没有DOM 1级事件。

1.DOM 0级事件

el.οnclick=function(){}

// 例1
var btn = document.getElementById('btn');
 btn.onclick = function(){
     alert(this.innerHTML);
 }

当希望为同一个元素/标签绑定多个同类型事件的时候(如给上面的这个btn元素绑定3个点击事件),是不被允许的。DOM0事件绑定,给元素的事件行为绑定方法,这些方法都是在当前元素事件行为的冒泡阶段(或者目标阶段)执行的

2.DOM 2级事件

el.addEventListener(event-name, callback, useCapture)

  • event-name: 事件名称,可以是标准的DOM事件

  • callback: 回调函数,当事件触发时,函数会被注入一个参数为当前的事件对象 event

  • useCapture: 默认是false,代表事件句柄在冒泡阶段执行

// 例2
var btn = document.getElementById('btn');
btn.addEventListener("click", test, false);
function test(e){
    e = e || window.event;
    alert((e.target || e.srcElement).innerHTML);
    btn.removeEventListener("click", test)
}
//IE9-:attachEvent()与detachEvent()。
//IE9+/chrom/FF:addEventListener()和removeEventListener()

IE9以下的IE浏览器不支持 addEventListener()和removeEventListener(),使用 attachEvent()与detachEvent() 代替,因为IE9以下是不支持事件捕获的,所以也没有第三个参数,第一个事件名称前要加on。

3.DOM 3级事件

在DOM 2级事件的基础上添加了更多的事件类型。

  • UI事件,当用户与页面上的元素交互时触发,如:load、scroll

  • 焦点事件,当元素获得或失去焦点时触发,如:blur、focus

  • 鼠标事件,当用户通过鼠标在页面执行操作时触发如:dblclick、mouseup

  • 滚轮事件,当使用鼠标滚轮或类似设备时触发,如:mousewheel

  • 文本事件,当在文档中输入文本时触发,如:textInput

  • 键盘事件,当用户通过键盘在页面上执行操作时触发,如:keydown、keypress

  • 合成事件,当为IME(输入法编辑器)输入字符时触发,如:compositionstart

  • 变动事件,当底层DOM结构发生变化时触发,如:DOMsubtreeModified

  • 同时DOM3级事件也允许使用者自定义一些事件。

二、DOM事件模型和事件流

DOM事件模型分为捕获和冒泡。一个事件发生后,会在子元素和父元素之间传播(propagation)。这种传播分成三个阶段。

(1)捕获阶段:事件从window对象自上而下向目标节点传播的阶段;

(2)目标阶段:真正的目标节点正在处理事件的阶段;

(3)冒泡阶段:事件从目标节点自下而上向window对象传播的阶段。

DOM事件捕获的具体流程

6c2d35e987c91128a6800d32b6743f02.png

捕获是从上到下,事件先从window对象,然后再到document(对象),然后是html标签(通过document.documentElement获取html标签),然后是body标签(通过document.body获取body标签),然后按照普通的html结构一层一层往下传,最后到达目标元素。

而事件冒泡的流程刚好是事件捕获的逆过程。
接下来我们看个事件冒泡的例子:

// 例3
"outer">
"inner">

......
window.onclick = function() {
    console.log('window');
};
document.onclick = function() {
    console.log('document');
};
document.documentElement.onclick = function() {
    console.log('html');
};
document.body.onclick = function() {
    console.log('body');
}
outer.onclick = function(ev) {
    console.log('outer');
};
inner.onclick = function(ev) {
    console.log('inner');
};
8a5bb9a1731dbb5a8ab2374457bb72a1.png

正如我们上面提到的onclick给元素的事件行为绑定方法都是在当前元素事件行为的冒泡阶段(或者目标阶段)执行的。

三、事件代理(事件委托)

由于事件会在冒泡阶段向上传播到父节点,因此可以把子节点的监听函数定义在父节点上,由父节点的监听函数统一处理多个子元素的事件。这种方法叫做事件的代理(delegation)。

1.优点

  • 减少内存消耗,提高性能

假设有一个列表,列表之中有大量的列表项,我们需要在点击每个列表项的时候响应一个事件

// 例4
<ul id="list">
  <li>item 1li>
  <li>item 2li>
  <li>item 3li>
  ......
  <li>item nli>
ul>

如果给每个列表项一一都绑定一个函数,那对于内存消耗是非常大的,效率上需要消耗很多性能。借助事件代理,我们只需要给父容器ul绑定方法即可,这样不管点击的是哪一个后代元素,都会根据冒泡传播的传递机制,把容器的click行为触发,然后把对应的方法执行,根据事件源,我们可以知道点击的是谁,从而完成不同的事。

  • 动态绑定事件

在很多时候,我们需要通过用户操作动态的增删列表项元素,如果一开始给每个子元素绑定事件,那么在列表发生变化时,就需要重新给新增的元素绑定事件,给即将删去的元素解绑事件,如果用事件代理就会省去很多这样麻烦。

2.如何实现

接下来我们来实现上例中父层元素 #list 下的 li 元素的事件委托到它的父层元素上:

// 给父层元素绑定事件
document.getElementById('list').addEventListener('click', function (e) {
  // 兼容性处理
  var event = e || window.event;
  var target = event.target || event.srcElement;
  // 判断是否匹配目标元素
  if (target.nodeName.toLocaleLowerCase === 'li') {
    console.log('the content is: ', target.innerHTML);
  }
});

四、Event对象常见的应用

  • event. preventDefault()

如果调用这个方法,默认事件行为将不再触发。什么是默认事件呢?例如表单一点击提交按钮(submit)跳转页面、a标签默认页面跳转或是锚点定位等。

很多时候我们使用a标签仅仅是想当做一个普通的按钮,点击实现一个功能,不想页面跳转,也不想锚点定位。

//方法一:
<a href="javascript:;">链接a>

也可以通过JS方法来阻止,给其click事件绑定方法,当我们点击A标签的时候,先触发click事件,其次才会执行自己的默认行为

//方法二:
<a id="test" href="http://www.cnblogs.com">链接a>
<script>
test.onclick = function(e){
    e = e || window.event;return false;
}script>
//方法三:
<a id="test" href="http://www.cnblogs.com">链接a>
<script>
test.onclick = function(e){
    e = e || window.event;
    e.preventDefault();
}script>

接下来我们看个例子:输入框最多只能输入六个字符,如何实现?

// 例5
 "text" id='tempInp'>
 <script>
    tempInp.onkeydown = function(ev) {
        ev = ev || window.event;let val = this.value.trim() //trim去除字符串首位空格(不兼容)// this.value=this.value.replace(/^ +| +$/g,'') 兼容写法let len = val.lengthif (len >= 6) {this.value = val.substr(0, 6);//阻止默认行为去除特殊按键(DELETE\BACK-SPACE\方向键...)let code = ev.which || ev.keyCode;if (!/^(46|8|37|38|39|40)$/.test(code)) {
                ev.preventDefault()
            }
        }
    }script>
  • event.stopPropagation() & event.stopImmediatePropagation()

event.stopPropagation() 方法阻止事件冒泡到父元素,阻止任何父事件处理程序被执行。上面提到事件冒泡阶段是指事件从目标节点自下而上向window对象传播的阶段。
我们在例4的inner元素click事件上,添加event.stopPropagation()这句话后,就阻止了父事件的执行,最后只打印了'inner'。

 inner.onclick = function(ev) {
    console.log('inner');
    ev.stopPropagation();
};

stopImmediatePropagation 既能阻止事件向父元素冒泡,也能阻止元素同事件类型的其它监听器被触发。而 stopPropagation 只能实现前者的效果。我们来看个例子:


  "btn">click me to stop propagation

......
const btn = document.querySelector('#btn');
btn.addEventListener('click', event => {
  console.log('btn click 1');
  event.stopImmediatePropagation();
});
btn.addEventListener('click', event => {
  console.log('btn click 2');
});
document.body.addEventListener('click', () => {
  console.log('body click');
});
// btn click 1

如上所示,使用 stopImmediatePropagation后,点击按钮时,不仅body绑定事件不会触发,与此同时按钮的另一个点击事件也不触发。

  • event.target & event.currentTarget

老实说这两者的区别,并不好用文字描述,我们先来看个例子:

<div id="a">
  <div id="b">
    <div id="c"><div id="d">div>div>
  div>
div>
<script>document.getElementById('a').addEventListener('click', function(e) {console.log('target:' + e.target.id + '&currentTarget:' + e.currentTarget.id
    )
  })document.getElementById('b').addEventListener('click', function(e) {console.log('target:' + e.target.id + '&currentTarget:' + e.currentTarget.id
    )
  })document.getElementById('c').addEventListener('click', function(e) {console.log('target:' + e.target.id + '&currentTarget:' + e.currentTarget.id
    )
  })document.getElementById('d').addEventListener('click', function(e) {console.log('target:' + e.target.id + '&currentTarget:' + e.currentTarget.id
    )
  })script>
4eb0201b222ac09e34bc0632ac5d3883.gif

当我们点击最里层的元素d的时候,会依次输出:

target:d&currentTarget:d
target:d&currentTarget:c
target:d&currentTarget:b
target:d&currentTarget:a

从输出中我们可以看到,event.target指向引起触发事件的元素,而event.currentTarget则是事件绑定的元素,只有被点击的那个目标元素的event.target才会等于event.currentTarget也就是说,event.currentTarget始终是监听事件者,而event.target是事件的真正发出者

五、参考文章

  • DOM级别与DOM事件

  • DOM事件机制解惑

  • 事件模型

  • JavaScript 事件委托详解

  • JavaScript 事件的学与记:stopPropagation 和 stopImmediatePropagation

  • event.target和event.currentTarget的区别

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/409820.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

如何开始了解一个新知识(Vuex)

我是歌谣 放弃很容易 但是坚持一定很酷 前言 每次做开发遇到一个新的知识点 总要思索着如何去实现这个新东西 最近来大概讲讲Vuex vuex是前端用的比较多的一个东西之一 通过一张图了解一下原理 原理和vuex产生原因 看完了整个的原理之后 安装就直接过去了 就是包管理工具 …

.Net Core 3.0下AOP试水~~

昨天躺了一下3.0的依赖注入的雷 今天顺势把AOP做了一下调整&#xff0c;比如自动化的AOP注入 默认的Program里面的CreateHostBuilder方法增加一行 public static IHostBuilder CreateHostBuilder(string[] args) >Host.CreateDefaultBuilder(args).UseServiceProviderFactor…

golang 读取文件最后一行_测试用例是开发人员最后一块遮羞布

测试用例是开发人员最后一块遮羞布最近一周写一个比较复杂的业务模块&#xff0c;越写到后面真心越心虚。操作越来越复杂了&#xff0c;代码也逐渐凌乱了起来。比如一个接口&#xff0c;传入的是一个比较复杂的大json&#xff0c;我需要解析这个大json&#xff0c;然后根据json…

android 进度条_Android仿水波纹流球进度条控制器,实现高端大气的主流特效

今天看到一个效果挺不错的&#xff0c;就模仿了下来&#xff0c;加上了一些自己想要的效果&#xff0c;感觉还不错的样子&#xff0c;所以就分享出来了&#xff0c;话不多说&#xff0c;上图CircleView这里主要是实现中心圆以及水波特效package com.lgl.circleview;import andr…

docker php composer 使用_如何使用Docker部署PHP开发环境

本文主要介绍了如何使用Docker构建PHP的开发环境&#xff0c;文中作者也探讨了构建基于Docker的开发环境应该使用单容器还是多容器&#xff0c;各有什么利弊。推荐PHP开发者阅读。希望对大家有所帮助。环境部署一直是一个很大的问题&#xff0c;无论是开发环境还是生产环境&…

from 下拉框多个值提交_Git提交规范

规范的作用大多数情况下&#xff0c;看提交历史的人跟提交代码的人都不是同一个人&#xff0c;当别人阅读你的提交历史时&#xff0c;他很可能是不知道具体代码细节的&#xff0c;你如何在最短的时间内让他一眼知道每次提交的意义&#xff1a;每次提交影响的具体范围&#xff1…

【物联网智能网关-03】GPRS模块中文短信收发

在去年年初&#xff0c;就已经推出V1.0.0的GPRS库&#xff0c;不过在这个版本上只是实现了西文短信收发和字符串方式的GPRS数据通信&#xff0c;功能还相对不完善&#xff08;参见我以前的博文《GPRS通信实现》&#xff09;。最近升级的版本&#xff0c;对以上功能进行了大幅度…

蓄电池单格电压多少伏_蓄电池充电规范手册

很多用户在买完蓄电池之后第一想法就是赶紧充电&#xff0c;很多陋习让用户使用行为造成了新买的蓄电池没怎么用感觉就和旧的没啥区别。而且使用时间越来越短到头来企业还失去了很多的客户&#xff0c;德国阳光蓄电池手册整理整编了在不同的环境中我们该如何很好的去维护自己的…

钉钉机器人关键词应答_除了用于电销,智能语音机器人可以应用哪些地方?

之前的文章探讨的是智能语音机器人在电销行业的应用&#xff0c;然而在实际的场景中&#xff0c;电销行业的应用只是大家所熟知的行业之一。对比于人工电销&#xff0c;使用智能语音机器人有着诸多优势&#xff0c;例如&#xff1a;工作效率高、意向筛选、电话录音并转化为文字…

1-2docker-基本的使用

1、Docker 官⽅提供了⼀个公共的镜像仓库 https://hub.docker.com2、获取镜像 docker pull [选项] [Docker Registry 地址[:端⼝]/]仓库名[:标签]3、运行镜像 docker run -it --rm ubuntu:16.04 /bin/bash -it&#xff1a;这是两个参数&#xff0c;⼀个是 -i&#xff1a;交互式…

assert函数_PHP 之 assert()函数

assert()函数其实是一个断言函数。那么什么是断言呢&#xff1f;百度百科上是这么说的&#xff1a;编写代码时&#xff0c;我们总是会做出一些假设&#xff0c;断言就是用于在代码中捕捉这些假设。说到这里&#xff0c;大家应该能知道assert()函数是干嘛用的了吧&#xff1f;好…

1-3docker commit定制镜像

以定制⼀个 Web 服务器为例⼦1、commit定制镜像 docker pull nginx:1.17运行容器 --name:容器名字 -d&#xff1a;后台 -p本地端口&#xff1a;容器内端口 docker run --name webserver -d -p 8080:80 nginx:1.17#进入容器 docker exec -it webserver /bin/bash#进入容器执…

mysql 启动_mysql安装、启动

在这个网址下载的&#xff1a;Download MySQL Community Server​dev.mysql.com下载后解压到了D盘&#xff0c;我是重命名为mysql。进去目录下bin子目录&#xff0c;进行以下操作&#xff0c;初始化&#xff1a;mysqld --initialize --console执行完成后&#xff0c;会输出 roo…

2010 Stanford Local ACM Programming Contest-H解题报告

题意是说&#xff0c;给出一些道路&#xff0c;要修建一条高速公路&#xff0c;高速公路不能分叉&#xff0c;而且是在给出的图中的一些路径组成&#xff0c;求的是不在高速公路上的点离高速公路的最远距离的最小值是多少。首先要找到一条这个图中的关键路径&#xff0c;既最长…

qtmessagebox对话框里自定义按钮文本_按钮你可以这样设计

作者&#xff1a;Michal Malewicz译者&#xff1a;Matrix审稿&#xff1a;afang原文链接&#xff1a;https://uxdesign.cc/design-better-buttons-a5c90a113280文章由交译所成员翻译&#xff0c;如需转载&#xff0c;请先申请授权。译文如下&#xff1a;按钮是触发它所描述功能…

zabbix入门之添加主机

添加主机的方法有两种&#xff1a;手动添加、自动发现 前提是&#xff1a;在被监控主机中安装zabbix-agent、zabbix-sender组件&#xff0c;并配置好启动服务。 手动添加&#xff1a; 自动发现&#xff1a; 这里等待1分钟左右即可发现主机 开启默认的动作 等待几分钟后即可在“…

如何保持连接_工高连城 | 连接器连接失效的原因有哪些

【温馨提示】本公众号是工高电子旗下工高连城中国连城双电商平台的官方公众号&#xff0c;简称工高连城连接器商城 中国连城平台定位&#xff1a;中国连接器行业专业供应链服务平台中国连接器行业的阿里巴巴永不落幕的online线上慕尼黑连接器展会。中国连城官网&#xff1a;w…

centos7删除文件命令_干货 | 玩转云文件存储——利用CFS实现web应用的共享访问...

京东云文件服务(Cloud File Service,以下简称&#xff1a;CFS)是一种高可靠、可扩展、可共享访问的全托管分布式文件系统。它可在不中断应用服务的情况下&#xff0c;根据您对文件系统的使用&#xff0c;按需扩展或缩减&#xff0c;并按照实际用量计费。采用NFS协议&#xff0c…

1-4dockerfile基本使用

1.创建一个文件夹 mkdir mynginxcd mynginxtouch Dockerfile [rootVM_0_10_centos mynginx]# cat Dockerfile FROM nginx:1.17 #第一次镜像RUN echo echo <h1>Hello, zjy!</h1> > /usr/share/nginx/html/index.html1-1、如果说没有第一层镜像&#xff0c;是…

zTree v2.6 - v3.0 文件对比

转载于:https://www.cnblogs.com/MyFlora/archive/2012/06/05/2536377.html