场景:

在启动3d虚拟仿真时注册一个keydown事件,用来触发3d基本体的复制粘贴操作

遇到的问题:

在这个页面有一个blocky积木块控制面板区域,调起这个面板,同样可以进行复制粘贴操作,而且快捷键一样,这就出现了在复制积木块的时候同时也进行了3d基本体的复制操作,在复制3d基本体同时也进行了复制积木块的操作

解决:

1、运用 document.activeElement 获取当前获得焦点的元素 ,判断是否为积木块区域,如果是,则不进行3d基本体的复制操作

2、在注册3d基本体keydown事件里面执行阻止冒泡操作,避免进行到积木块的复制操作

img

相关知识点:

区分不同区域的事件处理

  • 使用 closest 方法检查当前获得焦点的元素是否位于指定区域(例如 #blocklyDiv#customDiv)。
  • 根据事件来源区域执行不同的逻辑。

.stop修饰符:

.stop 是 Vue.js 事件修饰符之一,用于阻止事件传播(即阻止事件冒泡)。当你在 Vue 模板中使用 .stop 修饰符时,相当于在事件处理函数中调用了 event.stopPropagation()

语法:

1
<element @event.stop="handler"></element>

event.stopPropagation()

  • 作用:阻止事件冒泡,但不影响当前元素上其他事件处理器的执行。
  • 应用场景:当你希望阻止事件继续传播到父级元素,但允许当前元素上的其他事件处理器继续执行时使用。

event.stopImmediatePropagation()

  • 作用:立即停止事件传播,并阻止当前元素上任何后续事件处理器的执行。
  • 应用场景:当你希望阻止事件传播到父级元素,同时阻止当前元素上的所有其他事件处理器时使用。

区别

  • **event.stopPropagation()**

    • 只阻止事件冒泡到父级元素。
    • 当前元素上的其他事件处理器仍然会被执行。
  • **event.stopImmediatePropagation()**

    • 阻止事件冒泡到父级元素。
    • 阻止当前元素上任何后续事件处理器的执行。

为什么 event.stopImmediatePropagation() 生效而 event.stopPropagation() 不生效?

如果你的代码中 event.stopPropagation() 不生效,而 event.stopImmediatePropagation() 生效,可能是因为在同一元素上有多个事件处理器,你需要确保阻止所有事件处理器的执行。

示例

假设你有一个父 div 和一个子 div,并且你希望在子 div 上阻止 keydown 事件冒泡,并且不执行其他任何事件处理器:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<div id="app">
<div @keydown="parentKeydownHandler" style="border: 1px solid black; padding: 20px;">
Parent Div
<div @keydown="childKeydownHandler" tabindex="0" style="border: 1px solid red; padding: 20px; margin-top: 10px;">
Child Div
</div>
</div>
</div>

<script src="https://cdn.jsdelivr.net/npm/vue@2"></script>
<script>
new Vue({
el: '#app',
methods: {
parentKeydownHandler(event) {
console.log('Parent div keydown');
},
childKeydownHandler(event) {
console.log('Child div keydown');
event.stopImmediatePropagation(); // 阻止事件传播,并阻止其他事件处理器
// event.stopPropagation(); // 仅阻止事件冒泡,不阻止其他事件处理器
}
}
});
</script>

示例解释

  1. 父级 **div**
    • 绑定了 keydown 事件,触发 parentKeydownHandler 方法。
  1. 子级 **div**
    • 绑定了 keydown 事件,触发 childKeydownHandler 方法。
    • childKeydownHandler 方法中使用 event.stopImmediatePropagation() 来阻止事件传播并阻止其他事件处理器。

如果你使用 event.stopPropagation()

  • 事件将不会冒泡到父级 div,但当前元素(子 div)上的其他事件处理器仍然会被执行。

如果你使用 event.stopImmediatePropagation()

  • 事件将不会冒泡到父级 div,并且当前元素(子 div)上的其他事件处理器也不会被执行。

结论

  • 使用 event.stopPropagation() 来阻止事件冒泡,但允许当前元素上的其他事件处理器执行。
  • 使用 event.stopImmediatePropagation() 来立即阻止事件传播,并且阻止当前元素上的所有其他事件处理器执行。

理解: 如果两个keydown事件都绑定在document上,这个时候就不存在谁是谁父级的关系,只有使用event.stopImmediatePropagation()才生效 。

如果两个 keydown 事件监听器都绑定在 document 上,那么它们之间不存在父子关系。此时,event.stopPropagation() 无法阻止其他同级监听器的执行,因为它仅阻止事件的冒泡或捕获过程,而不是同一阶段的其他监听器的执行。

在这种情况下,如果你希望阻止同级监听器的执行,就需要使用 event.stopImmediatePropagation()。这个方法不仅会阻止事件传播,还会阻止当前目标上后续的事件监听器执行。

示例

假设你有两个 keydown 事件监听器都绑定在 document 上:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Event Propagation Example</title>
</head>
<body>
<div id="app">
<input type="text" placeholder="Press any key" />
</div>

<script>
document.addEventListener('keydown', function(event) {
console.log('First keydown listener');
// event.stopPropagation(); // This will not stop the second listener
event.stopImmediatePropagation(); // This will stop the second listener
});

document.addEventListener('keydown', function(event) {
console.log('Second keydown listener');
});
</script>
</body>
</html>

解释

  • 两个 **keydown** 监听器:都绑定在 document 上。
  • 使用 **event.stopPropagation()**:无法阻止第二个监听器的执行。
  • 使用 **event.stopImmediatePropagation()**:可以立即阻止第二个监听器的执行。

结论

  • **event.stopPropagation()**:只阻止事件在 DOM 树中的传播(冒泡或捕获),但不会阻止当前目标上其他同级监听器的执行。
  • **event.stopImmediatePropagation()**:不仅阻止事件传播,还会阻止当前目标上后续的事件监听器执行。在没有父子关系的情况下,使用 event.stopImmediatePropagation() 可以确保其他同级事件监听器不会被执行。