Web前端入门第 77 问:JavaScript 由程序触发绑定事件的几种方式
开发中经常会遇这样的需求:点击 A 元素的时候,需要触发 B 元素的事件,比如:点击一个 div 元素,然后触发 input:file 的 click 事件,用来选择文件上传。
click 方法
以上需求可通过元素的 click 方法触发:
<style>
.test2 {
padding: 4px;
margin-top: 12px;
}
</style>
<input type="file" class="test1"><br>
<button class="test2">前端路引--事件测试</button>
<script>
(() => {
const test1 = document.querySelector('.test1')
const test2 = document.querySelector('.test2')
test2.addEventListener('click', () => {
// 点击 test2 后,触发 test1 的 click 事件
test1.click()
})
})()
</script>
效果:

点击事件有 click 方法可以使用,如果需求是点击 A 元素触发 B 元素的 mousedown 事件,那能用 mousedown 方法吗?
<style>
button {
padding: 4px;
margin-top: 12px;
}
</style>
<button class="test1">前端路引--事件测试 test1</button><br>
<button class="test2">前端路引--事件测试 test2</button>
<script>
(() => {
const test1 = document.querySelector('.test1')
const test2 = document.querySelector('.test2')
test1.addEventListener('mousedown', () => {
console.log('test1 mousedown')
})
test2.addEventListener('click', () => {
// 点击 test2 后,触发 test1 的 click 事件
test1.click()
test1.mousedown();
})
})()
</script>
效果:

想法在实现上遇到了问题,html 元素上不存在 mousedown 方法,click 方法也只能触发 click 事件,无法触发绑定的 mousedown 事件,那么有办法可以做到吗?答案肯定是有的~~
dispatchEvent 方法
dispatchEvent 方法可以触发任意事件,其参数是一个实例化的 Event 对象。以上例子中使用 dispatchEvent 方法,实现效果如下:
<style>
button {
padding: 4px;
margin-top: 12px;
}
</style>
<button class="test1">前端路引--事件测试 test1</button><br>
<button class="test2">前端路引--事件测试 test2</button>
<script>
(() => {
const test1 = document.querySelector('.test1')
const test2 = document.querySelector('.test2')
test1.addEventListener('mousedown', () => {
console.log('test1 mousedown')
})
test2.addEventListener('click', () => {
// 点击 test2 后,触发 test1 的 click 事件
const event = new Event('mousedown')
test1.dispatchEvent(event)
})
})()
</script>
效果:

Event 对象
语法:
new Event(type, options)
该对象有两个参数:
第一个事件类型 type 为必传参数,不传则报错 Uncaught TypeError: Failed to construct 'Event': 1 argument required, but only 0 present.
第二个 options 参数为可选参数,拥有三个属性:
bubbles: 可选,Boolean 类型,默认值为 false,表示该事件是否冒泡。
cancelable: 可选,Boolean 类型,默认值为 false,表示该事件能否被取消。
composed: 可选,Boolean 类型,默认值为 false,指示事件是否会在影子 DOM 根节点之外触发侦听器。
bubbles 冒泡:
关于冒泡很好理解,就是子元素是否能冒泡到父元素,如下例子 test1 触发的事件将会冒泡到容器 test-container 上。
<div class="test-container">
<button class="test0">前端路引--事件测试 test0</button>
</div>
<button class="test1">前端路引--事件测试 test1</button>
<button class="test2">前端路引--事件测试 test2</button>
<script>
(() => {
const test0 = document.querySelector('.test0')
const test1 = document.querySelector('.test1')
const test2 = document.querySelector('.test2')
document.querySelector('.test-container').addEventListener('mousedown', () => {
console.log('test-container mousedown')
})
test1.addEventListener('click', () => {
// 默认不允许冒泡
const event = new Event('mousedown')
test0.dispatchEvent(event)
})
test2.addEventListener('click', () => {
// 配置 bubbles 允许冒泡
const event = new Event('mousedown', { bubbles: true })
test0.dispatchEvent(event)
})
})()
</script>
效果:

cancelable 事件能否取消:
true:表示事件是可取消的,调用 event.preventDefault() 会阻止浏览器的默认行为。
false:表示事件不可取消,调用 event.preventDefault() 无效。
实测就算传入的是传入为 false,也能调用 event.preventDefault() 并不会报错,对 Event 对象无效,但是对 MouseEvent 对象有用(参考后文)。
设置此参数可在事件的 event 参数上获取传入的值:
<input type="file" name="" id="" class="file"><br>
<button class="test1">前端路引--事件测试 cancelable: false</button><br>
<button class="test2">前端路引--事件测试 cancelable: true</button>
<script>
(() => {
const file = document.querySelector('.file')
const test1 = document.querySelector('.test1')
const test2 = document.querySelector('.test2')
file.addEventListener('click', () => {
console.log('cancelable', event.cancelable);
})
test1.addEventListener('click', () => {
const event = new Event('click', { cancelable: false })
file.dispatchEvent(event)
})
test2.addEventListener('click', () => {
const event = new Event('click', { cancelable: true })
file.dispatchEvent(event)
})
})()
</script>
效果:

dispatchEvent 触发的 Event 对象,并
不会响应元素本身的默认事件,比如 a 标签的跳转,input:file 的文件选择等。
composed 是否允许穿透 shadow DOM 节点:
如果不使用影子节点,这属性基本没啥用处,影子节点在常规开发中很少使用~~
一个简单示例:
<div class="wrapper">
<my-component id="host"></my-component>
</div>
<script>
(() => {
class MyComponent extends HTMLElement {
constructor() {
super();
const shadow = this.attachShadow({ mode: 'open' });
shadow.innerHTML = `
<button id="inner-button1">影子节点内部按钮1--前端路引</button>
<button id="inner-button2">影子节点内部按钮2--前端路引</button>
`;
}
}
customElements.define('my-component', MyComponent);
const host = document.querySelector('#host');
const innerBtn1 = host.shadowRoot.querySelector('#inner-button1')
const innerBtn2 = host.shadowRoot.querySelector('#inner-button2')
innerBtn1.addEventListener('click', () => {
const event = new Event('custom-event', {
bubbles: true, // 允许在 Shadow DOM 内部冒泡
composed: false // 禁止穿透到外部 DOM
});
innerBtn1.dispatchEvent(event);
});
innerBtn2.addEventListener('click', () => {
const event = new Event('custom-event', {
bubbles: true, // 允许在 Shadow DOM 内部冒泡
composed: true // 允许穿透到外部 DOM
});
innerBtn2.dispatchEvent(event);
});
// 尝试在外部 DOM 监听事件
host.addEventListener('custom-event', () => {
console.log('外部 DOM 监听到事件'); // 不会触发
});
})()
</script>
效果:

CustomEvent 对象
Event 对象没办法传入自定义数据,某些特定需求需要传入自定义参数时,可以祭出 CustomEvent 对象。
CustomEvent 继承 Event,所以 Event 支持的配置都支持,只是多了一个自定义数据字段。
示例:
<button class="test1">前端路引--事件测试 test1</button><br>
<button class="test2">前端路引--事件测试 test2</button>
<script>
(() => {
const test1 = document.querySelector('.test1')
const test2 = document.querySelector('.test2')
test1.addEventListener('dev', (event) => {
console.log('自定义数据:', event.detail);
})
test2.addEventListener('click', () => {
// 点击 test2 后,触发 test1 的 click 事件
const event = new CustomEvent('dev', {
detail: {
name: '前端路引',
age: 1
}
})
test1.dispatchEvent(event)
})
})()
</script>
以上代码使用了 CustomEvent 触发了自定义的 dev 事件,并传入了自定义数据。
效果:

MouseEvent
前面说了 dispatchEvent 触发的 Event 对象不会响应元素本身的默认事件,但可以通过 MouseEvent 对象来触发一些元素本身的默认事件。
如下例子:
<input type="file" name="" id="" class="file"><br>
<button class="test1">前端路引--事件测试 cancelable: false</button><br>
<button class="test2">前端路引--事件测试 cancelable: true</button>
<script>
(() => {
const file = document.querySelector('.file')
const test1 = document.querySelector('.test1')
const test2 = document.querySelector('.test2')
file.addEventListener('click', () => {
event.preventDefault()
console.log('cancelable', event.cancelable);
})
test1.addEventListener('click', () => {
const event = new MouseEvent('click', { cancelable: false })
const res = file.dispatchEvent(event)
console.log(`${!res ? '调用了' : '没调用'} preventDefault`);
})
test2.addEventListener('click', () => {
const event = new MouseEvent('click', { cancelable: true })
const res = file.dispatchEvent(event)
console.log(`${!res ? '调用了' : '没调用'} preventDefault`);
})
})()
</script>
效果:

dispatchEvent 返回值当 event 可被取消(cancelable 值为 true),且 event 中至少有一个事件处理程序调用了 Event.preventDefault() 方法时,返回 false。否则,返回 true。
写在最后
按照 MDN 的说法,由程序触发的事件,还有一个专用名词 合成事件,表示不是浏览器本身触发的事件。
除了本文例子中的几个 Event 对象外,还有一些其他对象,在使用时可参考 MDN 文档。
用户交互:
鼠标、键盘、触摸交互 MouseEvent, KeyboardEvent, TouchEvent
表单与输入:
输入框、表单提交 InputEvent, SubmitEvent
媒体控制:
音视频播放、设备流 MediaStreamTrackEvent
拖放与剪贴板:
拖拽操作、复制粘贴 DragEvent, ClipboardEvent
存储与通信:
本地存储、跨文档通信 StorageEvent, MessageEvent
错误与调试:
脚本错误捕获 ErrorEvent
设备与传感器:
方向、加速度检测 DeviceOrientationEvent
动画与过渡:
CSS 动画/过渡生命周期 AnimationEvent, TransitionEvent
Web前端入门第 77 问:JavaScript 由程序触发绑定事件的几种方式的更多相关文章
- WEB前端技巧之JQuery为动态添加的元素绑定事件.md
jquery 为动态添加的元素绑定事件 如果直接写click函数的话,只能把事件绑定在已经存在的元素上,不能绑定在动态添加的元素上 可以用delegate来实现 .delegate( select ...
- Javascript绑定事件的两种方式的区别
命名函数 <input type="button" onclick="check()" id="btn"/> <scrip ...
- web前端入坑第五篇:秒懂Vuejs、Angular、React原理和前端发展历史
秒懂Vuejs.Angular.React原理和前端发展历史 2017-04-07 小北哥哥 前端你别闹 今天来说说 "前端发展历史和框架" 「前端程序发展的历史」 「 不学自知, ...
- 基于MVC4+EasyUI的Web开发框架经验总结(12)--利用Jquery处理数据交互的几种方式
在基于MVC4+EasyUI的Web开发框架里面,大量采用了Jquery的方法,对数据进行请求或者提交,方便页面和服务器后端进行数据的交互处理.本文主要介绍利用Jquery处理数据交互的几种方式,包括 ...
- 使用 JavaScript 的 HTML 页面混合、JavaScript 文件引用和 HTML 代码嵌入 3 种方式在 HTML 页面上打印出“点击我进入到百度首页”的超链接
查看本章节 查看作业目录 需求说明: 使用 JavaScript 的 HTML 页面混合.JavaScript 文件引用和 HTML 代码嵌入 3 种方式在 HTML 页面上打印出"点击我进 ...
- web前端入坑第二篇:web前端到底怎么学?干货资料! 【转】
http://blog.csdn.net/xllily_11/article/details/52145172 版权声明:本文为博主[小北]原创文章,如要转载请评论回复.个人前端公众号:前端你别闹,J ...
- web前端(13)—— 了解JavaScript,JavaScript的引入方式
从本篇博文开始,将进入web前端方便最关键最重要的部分——javascript,学到后面你就知道它真的太重要了 什么是JavaScript JavaScript一种直译式的脚本语言,是一种动态类型.弱 ...
- WEB前端工程师整理的原生JavaScript经典百例
一.原生JavaScript实现字符串长度截取 二.原生JavaScript获取域名主机 三.原生JavaScript转义html标签 四.原生JavaScript时间日期格式替换 Date.prot ...
- Web前端基础怎么学? JavaScript、html、css知识架构图
以前开发者只要掌握 HTML.CSS.JavaScript 三驾马车就能胜任一份前端的工作了.而现在除了普通的编码以外,还要考虑如何性能优化,如何跨端.跨平台实现功能,尤其是 AI.5G 技术的来临, ...
- web前端——实例中学习css,javascript
最近闲暇时候在研究前端的样式和js,以前都是从w3school上看看那些选择器和DOM操作方法很少去实际做demo来研究,做的过程当中才真切感觉到纸上得来终觉浅,看得懂跟能做出东西完全两码事,尤其在定 ...
随机推荐
- Linux防火墙操作指令
firewall-cmd --list-ports # 查看开放的端口号 firewall-cmd --zone=public --add-port=8888/tcp --permanent # 开放 ...
- 康谋产品 | 用于ADAS和AD传感器的独立数据采集设备
一.产品简介 在 ADAS/AD 环境中,如果想要将原始数据与摄像头.雷达或激光雷达等传感器分离,总是会使用测量数据转换器.借助MDILink,您可以获得一个SerDes测量数据转换器,从开发阶段和验 ...
- Java--通过jdbc访问mysql数据库(mysql v8.0.11)
由于mysql的更新,原来的连接数据库方法改变了 参考:http://www.cnblogs.com/rainbow70626/p/9005852.html package demo; import ...
- IDEA问题之“调整IDEA字体大小”
调整IDEA字体大小 1.正常版 2. 远程版
- SQL 强化练习 (六)
本以为学会了Python 就已经天下无敌, 果然, 我还是太傻太天真了. 业务中几乎就没有用 Python 来直接连接数据库进行操作, 当然我是说数据这块哈. 哎, 难受, 还是用的 sql 这种方式 ...
- AI法律助手:打造普惠法律服务的未来
当法律服务遇见人工智能,普通人的维权之路将不再艰难 当法律服务成为奢侈品,AI或许是唯一出路 2025年的一个深夜,我刷着手机,一条新闻让我停下了滑动的手指: "某平台家装工人因合同纠纷讨薪 ...
- 京东首页html+css1.0
小菜鸟的学习记录,还望各位猿兄不吝赐教 文章目录 效果图 源码 HTML文件 css文件 效果图 源码 HTML文件 <!DOCTYPE html> <html> <he ...
- @FeignClient注解自定义接口超时时间
问题描述 每个微服务都有统一的接口超时时间设定,但也存在一些特殊的业务场景,其接口需要较长的超时时间,比如:导出excel报表.上传文件.拉取业务报表数据等等.此时,默认的超时设置就不能满足需求, ...
- 玩客云 OEC/OECT 笔记
外观 内部 PCB正面 PCB背面 PCB背面 RK3566 1Gbps PHY 配置 OEC 和 OECT(OEC-turbo) 都是基于瑞芯微 RK3566/RK3568 的网络盒子, 没有HDM ...
- 理解 .NET 结构体字段的内存布局
目录 前言 基本概念 结构体的默认字段布局 对齐 64 位系统与 32 位系统的对齐要求差异 默认字段布局中 对齐要求 与 偏移量 的关系 填充 包含引用类型字段的结构体的默认字段布局 用 Struc ...