取消事件冒泡
Konva 的事件会从图形向上冒泡到分组、图层、舞台。需要时可以中断这个过程。
用法
要使用Konva阻止冒泡,我们可以设置cancelBubble对象的属性设置为true。
说明:点击圆形可以观察到只有圆形事件绑定被触发, 因为事件传播在触发循环事件时被取消,防止事件对象向上冒泡。
<!DOCTYPE html>
<html>
<head>
<script src="https://unpkg.com/konva@10/konva.min.js"></script>
<meta charset="utf-8">
<title>Konva Cancel Event Bubble Propagation Demo</title>
<style>
body {
margin: 0;
padding: 0;
overflow: hidden;
background-color: #F0F0F0;
}
</style>
</head>
<body>
<div id="container"></div>
<script>
var stage = new Konva.Stage({
container: 'container',
width: 300,
height: 300
});
var layer = new Konva.Layer();
var group = new Konva.Group();
var circle = new Konva.Circle({
x: stage.getWidth() / 2,
y: stage.getHeight() / 2,
radius: 70,
fill: 'red',
stroke: 'black',
strokeWidth: 4
});
circle.on('click', function(evt) {
alert('You clicked the circle!');
evt.cancelBubble = true;
});
group.on('click', function() {
alert('You clicked on the group!');
});
layer.on('click', function() {
alert('You clicked on the layer!');
});
group.add(circle);
layer.add(group);
// add the layer to the stage
stage.add(layer);
</script>
</body>
</html>
常见问题
cancelBubble 是属性还是方法?
是属性赋值,不是方法调用:
shape.on('click', (e) => {
e.cancelBubble = true;
});
写成 e.cancelBubble() 会抛错。这个命名沿袭自早期 IE 的事件模型,
和 DOM 标准的 stopPropagation() 不是一回事。
阻止了冒泡,为什么外层的 DOM 事件还是触发了?
cancelBubble 只管 Konva 内部的节点冒泡链——图形到分组到图层到舞台。
它不影响原生 DOM 事件继续往 <canvas> 外面传。
要拦住原生事件,操作真实事件对象:
e.evt.stopPropagation();
两者经常需要一起用:前者防止舞台的点击处理器把选中态清空, 后者防止页面上的其他监听器响应。
舞台的 content 事件能被 cancelBubble 阻止吗?
不能。contentClick、contentMousemove 这类事件由舞台自己派发,
不在图形的冒泡链上,图形里设 cancelBubble 对它们没有任何影响。
如果你同时用了这两套机制,要意识到它们是并行的——点一个图形,
图形的 click 和舞台的 contentClick 都会触发。详见 Stage 事件。
与其他方案的取舍
除了阻止冒泡,还有一种常见做法是在外层处理器里判断 e.target:
layer.on('click', (e) => {
if (e.target !== background) return;
// 只处理点在背景上的情况
});
两者的区别在于控制权在哪一侧。cancelBubble 是内层决定「这个事件到我为止」,
外层无从知晓;判断 e.target 是外层自己筛选,内层什么都不用做。
组件化的场景更适合前者——子组件封装自己的行为,不需要外层配合。 而外层逻辑集中的场景用后者更清楚,因为所有分支都写在一处,不必到处找谁阻止了冒泡。