HTML5 Canvas 监听禁用性能提示
如果你在画布上有很多形状,并且不需要对其中某些形状检测事件,
你可以将 listening
设置为 false
来提高性能。
当 listening = false
时,该形状将被忽略事件检测(如鼠标悬停、拖放、点击等)。
这可以显著提高复杂应用的性能。
下面是一个演示,展示了监听形状与非监听形状之间的性能差异:
- Vanilla
- React
- Vue
import Konva from 'konva'; const stage = new Konva.Stage({ container: 'container', width: window.innerWidth, height: window.innerHeight, }); const layer = new Konva.Layer(); stage.add(layer); // 创建许多启用事件监听的圆圈 for (let i = 0; i < 100; i++) { const circle = new Konva.Circle({ x: Math.random() * stage.width(), y: Math.random() * stage.height(), radius: 20, fill: 'blue', opacity: 0.5, // 启用事件检测(默认) listening: true, }); // 添加悬停效果 circle.on('mouseover', function() { this.fill('red'); }); circle.on('mouseout', function() { this.fill('blue'); }); layer.add(circle); } // 创建许多禁用事件监听的圆圈 for (let i = 0; i < 1000; i++) { const circle = new Konva.Circle({ x: Math.random() * stage.width(), y: Math.random() * stage.height(), radius: 20, fill: 'green', opacity: 0.5, // 禁用事件检测以获得更好的性能 listening: false, }); layer.add(circle); } // 添加文本说明 const text = new Konva.Text({ x: 10, y: 10, text: '蓝色圆圈(100)有事件监听(悬停它们)\n绿色圆圈(1000)没有监听(更好的性能)', fontSize: 16, fill: 'black', }); layer.add(text);
import { Stage, Layer, Circle, Text } from 'react-konva'; import { useState } from 'react'; const App = () => { const [hoveredId, setHoveredId] = useState(null); // 生成圆圈数据 const listeningCircles = Array.from({ length: 100 }, (_, i) => ({ id: i, x: Math.random() * window.innerWidth, y: Math.random() * window.innerHeight, })); const nonListeningCircles = Array.from({ length: 1000 }, (_, i) => ({ id: i + 100, x: Math.random() * window.innerWidth, y: Math.random() * window.innerHeight, })); return ( <Stage width={window.innerWidth} height={window.innerHeight}> <Layer> {/* 含事件监听的圆圈 */} {listeningCircles.map((circle) => ( <Circle key={circle.id} x={circle.x} y={circle.y} radius={20} fill={hoveredId === circle.id ? 'red' : 'blue'} opacity={0.5} onMouseEnter={() => setHoveredId(circle.id)} onMouseLeave={() => setHoveredId(null)} /> ))} {/* 不含事件监听的圆圈 */} {nonListeningCircles.map((circle) => ( <Circle key={circle.id} x={circle.x} y={circle.y} radius={20} fill="green" opacity={0.5} listening={false} /> ))} <Text x={10} y={10} text="蓝色圆圈(100)有事件监听(悬停它们)\n绿色圆圈(1000)没有监听(更好的性能)" fontSize={16} fill="black" /> </Layer> </Stage> ); }; export default App;
<template> <v-stage :config="stageSize"> <v-layer> <!-- 含事件监听的圆圈 --> <v-circle v-for="circle in listeningCircles" :key="circle.id" :config="getListeningCircleConfig(circle)" @mouseenter="handleMouseEnter(circle.id)" @mouseleave="handleMouseLeave" /> <!-- 不含事件监听的圆圈 --> <v-circle v-for="circle in nonListeningCircles" :key="circle.id" :config="getNonListeningCircleConfig(circle)" /> <v-text :config="textConfig" /> </v-layer> </v-stage> </template> <script setup> import { ref } from 'vue'; const stageSize = { width: window.innerWidth, height: window.innerHeight }; const hoveredId = ref(null); // 生成圆圈数据 const listeningCircles = Array.from({ length: 100 }, (_, i) => ({ id: i, x: Math.random() * window.innerWidth, y: Math.random() * window.innerHeight, })); const nonListeningCircles = Array.from({ length: 1000 }, (_, i) => ({ id: i + 100, x: Math.random() * window.innerWidth, y: Math.random() * window.innerHeight, })); const getListeningCircleConfig = (circle) => ({ x: circle.x, y: circle.y, radius: 20, fill: hoveredId.value === circle.id ? 'red' : 'blue', opacity: 0.5, }); const getNonListeningCircleConfig = (circle) => ({ x: circle.x, y: circle.y, radius: 20, fill: 'green', opacity: 0.5, listening: false, }); const textConfig = { x: 10, y: 10, text: '蓝色圆圈(100)有事件监听(悬停它们)\n绿色圆圈(1000)没有监听(更好的性能)', fontSize: 16, fill: 'black', }; const handleMouseEnter = (id) => { hoveredId.value = id; }; const handleMouseLeave = () => { hoveredId.value = null; }; </script>