JS 也可以生成事件:
click、mousedown),这可能会有助于自动化测试类似于 [[002.DOM:节点与集合#DOM 节点层次结构|DOM 元素类]],事件类也形成一个 层次结构(hierarchy):
![[Pasted image 20240429172246.png]]
Eventnew Event(type: string, options?)
type:事件名称options:对象
bubbles?: boolean:默认 false,表示该事件是否冒泡,[[008.事件概况#事件传播流程|事件传播流程]]cancelable?: boolean:默认 false,表示该事件是否可被取消,[[008.事件概况#不可取消事件|浏览器默认行为]]composed?: boolean:默认 false,指示事件是否会在影子 DOM 根节点之外触发侦听器CustomEventnew CustomEvent(type: string, options?)
CustomEventCustomEvent 和 Event 一样,只有一点不同:
options.detail?: any:添加自定义数据event.detail 只读属性获取自定义数据从技术上讲,可以不用 detail,因为可以在创建后将任何属性分配给常规的 new Event 对象中。但是 CustomEvent 提供了特殊的 detail 字段,以避免与其他事件属性的冲突
XxxEvent如果想要创建内建事件,应该使用具体的内建事件(如:new MouseEvent("click")),而不是 new Event
正确的构造器允许为该类型的事件指定标准属性,如:
const event = new MouseEvent("click", {
bubbles: true,
cancelable: true,
clientX: 100,
clientY: 100
})
console.log(event.clientX) // 100
通用的 Event 构造器不允许这样做:
const event = new Event("click", {
bubbles: true, // 只有 bubbles 和 cancelable 可以工作
cancelable: true,
clientX: 100,
clientY: 100
})
console.log(event.clientX) // undefined,未知的属性被忽略了
从技术上讲,可以通过在创建后直接分配 event.clientX = 100 来解决这个问题。所以,这是一个方便和遵守规则的问题。浏览器生成的事件始终具有正确的类型
EventTarget.dispatchEvent(event: Event)
event:被派发的 Event,其 event.target 为当前 EventTargetevent.isTrusted:区分“真实”用户事件和通过脚本生成的事件
true:来自真实用户操作的事件false:脚本生成的事件<h1 id="elem">Hello from the script!</h1>
<script>
// 监听事件
elem.addEventListener("hello", (e) => {
console.log(e.target) // elem
})
// 创建事件
const event = new Event("hello")
// 虽然 Event 可以正确工作,但是自定义事件还是推荐 CustomEvent
// 分派该事件
elem.dispatchEvent(event)
</script>
冒泡示例:
<h1 id="elem">Hello from the script!</h1>
<script>
// 在 document 上监听
document.addEventListener("hello", function(event) {
console.log(event.detail.a); // test
})
// 在 elem 上 dispatch
const event = new CustomEvent("hello", {
bubbles: true, // 允许冒泡
detail: { a: 'test' } // 自定义数据
})
elem.dispatchEvent(event);
</script>
注意:自定义事件应该使用 addEventListener,因为 on<event> 仅存在于内建事件中,document.onhello 则无法运行
<button id="elem" onclick="alert('Click!');">Autoclick</button>
<script>
const event = new Event("click")
// 虽然 Event 可以正确工作,但是内建事件还是推荐 MouseEvent
elem.dispatchEvent(event)
</script>
尽管技术上可以生成和触发浏览器内建事件,但还是应谨慎使用它们
因为这是运行处理程序的一种怪异(hacky)方式。大多数时候,这都是糟糕的架构
可以生成原生事件的场景:
通常事件是在队列中处理的。也就是说:如果浏览器正在处理 onclick,这时发生了一个新的事件,例如鼠标移动了,那么它的处理程序会被排入队列,相应的 mousemove 处理程序将在 onclick 事件处理完成后被调用
值得注意的例外情况就是,一个事件是在另一个事件中发起的(如:使用 dispatchEvent、调用触发其他事件的方法),这类事件将会被立即处理,即在新的事件处理程序被调用之后,恢复到当前的事件处理程序
例如:
<button id="menu">Menu (click me)</button>
<script>
menu.onclick = function() {
console.log(1)
menu.dispatchEvent(new CustomEvent("menu-open", {
bubbles: true
}))
console.log(2)
};
document.addEventListener('menu-open', () => console.log('nested'))
</script>
结果是:1 -> nested -> 2
如果想要当前事件处理函数不被打断,可以将其放到下一个 [[008.事件循环|事件循环]] 中触发:
<button id="menu">Menu (click me)</button>
<script>
menu.onclick = function() {
console.log(1)
// 放到下一个事件循环中触发事件
setimeout(() => menu.dispatchEvent(new CustomEvent("menu-open", {
bubbles: true
})))
console.log(2)
};
document.addEventListener('menu-open', () => console.log('nested'))
</script>
结果是:1 -> 2 -> nested