写点什么

Web 前端入门:JavaScript 由程序触发绑定事件的几种方式

  • 2025-07-15
    福建
  • 本文字数:4652 字

    阅读完需:约 15 分钟

开发中经常会遇这样的需求:点击 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 文档。


用户交互:鼠标、键盘、触摸交互 MouseEventKeyboardEventTouchEvent

表单与输入:输入框、表单提交 InputEventSubmitEvent

媒体控制:音视频播放、设备流 MediaStreamTrackEvent

拖放与剪贴板:拖拽操作、复制粘贴 DragEventClipboardEvent

存储与通信:本地存储、跨文档通信 StorageEventMessageEvent

错误与调试:脚本错误捕获 ErrorEvent

设备与传感器:方向、加速度检测 DeviceOrientationEvent

动画与过渡:CSS 动画/过渡生命周期 AnimationEventTransitionEvent


文章转载自:前端路引

原文链接:https://www.cnblogs.com/linx/p/18983403

体验地址:http://www.jnpfsoft.com/?from=001YH

用户头像

还未添加个人签名 2025-04-01 加入

还未添加个人简介

评论

发布
暂无评论
Web前端入门:JavaScript 由程序触发绑定事件的几种方式_JavaScript_量贩潮汐·WholesaleTide_InfoQ写作社区