开发中经常会遇这样的需求:点击 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 由程序触发绑定事件的几种方式的更多相关文章

  1. WEB前端技巧之JQuery为动态添加的元素绑定事件.md

      jquery 为动态添加的元素绑定事件 如果直接写click函数的话,只能把事件绑定在已经存在的元素上,不能绑定在动态添加的元素上 可以用delegate来实现 .delegate( select ...

  2. Javascript绑定事件的两种方式的区别

    命名函数 <input type="button" onclick="check()" id="btn"/> <scrip ...

  3. web前端入坑第五篇:秒懂Vuejs、Angular、React原理和前端发展历史

    秒懂Vuejs.Angular.React原理和前端发展历史 2017-04-07 小北哥哥 前端你别闹 今天来说说 "前端发展历史和框架" 「前端程序发展的历史」 「 不学自知, ...

  4. 基于MVC4+EasyUI的Web开发框架经验总结(12)--利用Jquery处理数据交互的几种方式

    在基于MVC4+EasyUI的Web开发框架里面,大量采用了Jquery的方法,对数据进行请求或者提交,方便页面和服务器后端进行数据的交互处理.本文主要介绍利用Jquery处理数据交互的几种方式,包括 ...

  5. 使用 JavaScript 的 HTML 页面混合、JavaScript 文件引用和 HTML 代码嵌入 3 种方式在 HTML 页面上打印出“点击我进入到百度首页”的超链接

    查看本章节 查看作业目录 需求说明: 使用 JavaScript 的 HTML 页面混合.JavaScript 文件引用和 HTML 代码嵌入 3 种方式在 HTML 页面上打印出"点击我进 ...

  6. web前端入坑第二篇:web前端到底怎么学?干货资料! 【转】

    http://blog.csdn.net/xllily_11/article/details/52145172 版权声明:本文为博主[小北]原创文章,如要转载请评论回复.个人前端公众号:前端你别闹,J ...

  7. web前端(13)—— 了解JavaScript,JavaScript的引入方式

    从本篇博文开始,将进入web前端方便最关键最重要的部分——javascript,学到后面你就知道它真的太重要了 什么是JavaScript JavaScript一种直译式的脚本语言,是一种动态类型.弱 ...

  8. WEB前端工程师整理的原生JavaScript经典百例

    一.原生JavaScript实现字符串长度截取 二.原生JavaScript获取域名主机 三.原生JavaScript转义html标签 四.原生JavaScript时间日期格式替换 Date.prot ...

  9. Web前端基础怎么学? JavaScript、html、css知识架构图

    以前开发者只要掌握 HTML.CSS.JavaScript 三驾马车就能胜任一份前端的工作了.而现在除了普通的编码以外,还要考虑如何性能优化,如何跨端.跨平台实现功能,尤其是 AI.5G 技术的来临, ...

  10. web前端——实例中学习css,javascript

    最近闲暇时候在研究前端的样式和js,以前都是从w3school上看看那些选择器和DOM操作方法很少去实际做demo来研究,做的过程当中才真切感觉到纸上得来终觉浅,看得懂跟能做出东西完全两码事,尤其在定 ...

随机推荐

  1. python,数据拼接举例

    request请求参数data =  '{"TwitterId":123456,"SupperId":0}' data内的123456,实际是个变量,且数据来源 ...

  2. mac系统安装GNU-sed

    经过网上查资料,发现 由于 mac 系统与 linux 系统的差异,mac自带的sed命令,因为其是基于bsd,所以与常用的gnu不一样,安装gnu-sed 可正常使用: 1.brew install ...

  3. .net core日志NLog的使用

    Nlog日志使用 视频:https://www.bilibili.com/video/BV1bv4y1a79X 参照:https://www.cnblogs.com/sheng-jie/p/17169 ...

  4. .Net Core全局的json配置

    .Net Core全局的json配置 参照文档: 怎样将枚举展示成字符串类型:https://code-maze.com/csharp-serialize-enum-to-string/ 全局配置:a ...

  5. Kali安装JDK8以及JDK11、JDK17切换

    声明:本文分享的安全工具和项目均来源于网络,仅供安全研究与学习之用, 如用于其他用途,由使用者承担全部法律及连带责任,与工具作者和本公众号无关. 瓜神学习网络安全 公众号 背景 很久之前更新了一次ka ...

  6. nacos安装

    linux-docker 下载nacos docker pull nacos/nacos-server:v2.2.3 `` ## 下载git脚本 ```shell cd /prod mkdir nac ...

  7. 自定义工具类之”判断两个集合中是否有一个相同的值-》CollectionUtils.containsAny(集合1,集合2)“

    判断两个集合中是否有一个相同的值 CollectionUtils.containsAny(集合1,集合2)就可以满足以下条件 两个集合中,只要有一个值相同就直接返回true 如:集合1:"1 ...

  8. SQL 强化练习 (五)

    果然日常练练这些 sql 是非常有必要的, 这几日的报表开发, 用一款过程软件 fineReport, 相对于我之前用 Tableau 来做报表, 这个帆软, 确实更加适合中国人哦, 而Tableau ...

  9. 基于onnxruntime结合PyQt快速搭建视觉原型Demo

      我在日常工作中经常使用PyQt和onnxruntime来快速生产demo软件,用于展示和测试,这里,我将以Yolov12为例,展示一下我的方案.   首先我们需要使用Yolov12训练一个模型,并 ...

  10. 摸鱼神器:打造一款让VS Code成为你私人影院的插件

    @charset "UTF-8"; .markdown-body { line-height: 1.75; font-weight: 400; font-size: 15px; o ...