开发中经常会遇这样的需求:点击 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. web自动化的鼠标操作

    有些场景不适合点击或进行某些操作,可运用action类模拟鼠标操作.在操作一个页面元素时有时需要一连串的动作来配合的时候,可以使用action来完成. Actions actions= new Act ...

  2. webapi里调用grpc

    参照:ASP .NET Core 6.0使用Grpc配置服务和调用服务_asp.net core grpc 服务-CSDN博客 demo:https://files.cnblogs.com/files ...

  3. python 处理word 分页符、分节符

    import docx doc1 =docx.Document(r"C:\Users\Administrator\Desktop\test.docx") doc1.paragrap ...

  4. 【经验】Git|Windows下如何管理和部署多个Git账号的SSH密钥文件

    生成 SSH 密钥 先打开一个git窗口,生成ssh密钥. 如果打开的不是git窗口,而是cmd窗口,则需要先切换到C:\Users\用户名\.ssh目录下. 下面这条指令的your_email和yo ...

  5. QtWidget项目-仿腾讯QQ音乐

    本博客主要介绍本人写的个人项目 - QtWidget5 仿腾讯QQ音乐项目. 效果演示 项目详情 源码 Gitee地址:https://gitee.com/run-little-peach/my-qq ...

  6. C#之Bitmap

    SetPixel和GetPixel private void btnC_Click(object sender, RoutedEventArgs e) { OpenFileDialog dia = n ...

  7. odoo里面的动作

    来源:Odoo中的五种action都是继承自ir.actions.actions模型实现的子类,共有五种,下面会一个一个给出具体例子 1.链接Action(ir.actions.act_url):ta ...

  8. MyBatis常见面试题:通常一个Xml映射文件,都会写一个Dao接口与之对应,请问,这个Dao接口的工作原理是什么?Dao接口里的方法,参数不同时,方法能重载吗?

      MyBatis常见面试题:通常一个Xml映射文件,都会写一个Dao接口与之对应,请问,这个Dao接口的工作原理是什么?Dao接口里的方法,参数不同时,方法能重载吗?   Dao接口即Mapper接 ...

  9. github无法访问问题解决方法

    问题描述: 直接使用gtihub.com网址访问github浏览器无响应. 解决办法: 1.登录https://github.com.ipaddress.com/去查询github.com.githu ...

  10. CentOS7 vsftpd服务搭建与详解

    FTP介绍 文件传输协议(File Transfer Protocol,FTP),基于该协议FTP客户端与服务端可以实现共享文件.上传文件.下载文件. FTP 基于TCP协议生成一个虚拟的连接,主要用 ...