拖放压力测试与10,000个形状
本示例展示了一个包含10,000个形状的压力测试。为简化操作,我们只使用了两个图层 - 一个主要图层用于所有形状,一个专用的拖动图层。当我们拖动一个形状时,它会移动到单独的拖动图层上,以确保移动的流畅性。
- Vanilla
- React
- Vue
import Konva from 'konva'; const width = window.innerWidth; const height = window.innerHeight; // 创建舞台 const stage = new Konva.Stage({ container: 'container', width: width, height: height, }); // 创建用于所有形状的主要图层 const mainLayer = new Konva.Layer(); // 创建一个专用图层用于拖动 const dragLayer = new Konva.Layer(); // 定义随机形状的颜色 const colors = [ 'red', 'orange', 'yellow', 'green', 'blue', 'cyan', 'purple', ]; let colorIndex = 0; // 辅助函数,将圆添加到图层 function addCircle(layer) { const color = colors[colorIndex++]; if (colorIndex >= colors.length) { colorIndex = 0; } const randX = Math.random() * stage.width(); const randY = Math.random() * stage.height(); const circle = new Konva.Circle({ x: randX, y: randY, radius: 6, fill: color, }); layer.add(circle); } // 在主要图层上创建10,000个圆 for (let n = 0; n < 10000; n++) { addCircle(mainLayer); } // 将主要图层和拖动图层添加到舞台 stage.add(mainLayer); stage.add(dragLayer); // 设置拖放行为 stage.on('mousedown', function (evt) { const circle = evt.target; // 仅处理圆形(忽略在空白区域的点击) if (!circle || circle.getClassName() !== 'Circle') { return; } // 将圆形移动到拖动图层 circle.moveTo(dragLayer); circle.startDrag(); }); // 当拖动停止时,将圆形 移动回主要图层 stage.on('mouseup', function (evt) { const circle = evt.target; // 仅处理圆形 if (!circle || circle.getClassName() !== 'Circle') { return; } // 将圆形移回主要图层 circle.moveTo(mainLayer); });
import { useState, useEffect, useRef } from 'react'; import { Stage, Layer, Circle } from 'react-konva'; const COLORS = ['red', 'orange', 'yellow', 'green', 'blue', 'cyan', 'purple']; const SHAPE_COUNT = 10000; const App = () => { // 用于存储所有圆形数据的状态 const [circles, setCircles] = useState([]); // 图层的refs const mainLayerRef = useRef(null); const dragLayerRef = useRef(null); // 初始化圆形数据 useEffect(() => { const circlesData = []; // 创建10,000个圆形 for (let i = 0; i < SHAPE_COUNT; i++) { circlesData.push({ id: i, x: Math.random() * window.innerWidth, y: Math.random() * window.innerHeight, radius: 6, fill: COLORS[i % COLORS.length] }); } setCircles(circlesData); }, []); // 这不是典型的“React方式”管理组件。 // 在更符合React的方式中,我们会更新状态,并让React处理DOM。 // 然而为了本性能演示,我们直接操作节点 // 以匹配原生JS实现。 const handleDragStart = (e) => { const target = e.target; // 将圆形移动到拖动图层 target.moveTo(dragLayerRef.current); }; const handleDragEnd = (e) => { const target = e.target; // 将圆形移回主要图层 target.moveTo(mainLayerRef.current); }; return ( <Stage width={window.innerWidth} height={window.innerHeight}> {/* 用于所有圆形的主要图层 */} <Layer ref={mainLayerRef}> {circles.map(circle => ( <Circle key={circle.id} id={circle.id} x={circle.x} y={circle.y} radius={circle.radius} fill={circle.fill} draggable onDragStart={handleDragStart} onDragEnd={handleDragEnd} /> ))} </Layer> {/* 空拖动图层,在拖动期间接收圆形 */} <Layer ref={dragLayerRef} /> </Stage> ); }; export default App;
<template> <v-stage :config="stageConfig"> <!-- 用于所有圆形的主要图层 --> <v-layer ref="mainLayer"> <v-circle v-for="circle in circles" :key="circle.id" :config="{ id: circle.id, x: circle.x, y: circle.y, radius: 6, fill: circle.fill, draggable: true }" @dragstart="handleDragStart" @dragend="handleDragEnd" /> </v-layer> <!-- 空拖动图层,在拖动期间接收圆形 --> <v-layer ref="dragLayer" /> </v-stage> </template> <script setup> import { ref, onMounted } from 'vue'; const COLORS = ['red', 'orange', 'yellow', 'green', 'blue', 'cyan', 'purple']; const SHAPE_COUNT = 10000; const stageConfig = { width: window.innerWidth, height: window.innerHeight }; // 图层的refs const mainLayer = ref(null); const dragLayer = ref(null); // 圆形的状态 const circles = ref([]); // 初始化圆形数据 onMounted(() => { const circlesData = []; // 创建10,000个圆形 for (let i = 0; i < SHAPE_COUNT; i++) { circlesData.push({ id: i, x: Math.random() * stageConfig.width, y: Math.random() * stageConfig.height, radius: 6, fill: COLORS[i % COLORS.length] }); } circles.value = circlesData; }); // 这不是典型的“Vue方式”管理组件。 // 在更符合Vue的方式中,我们会更新状态,并让Vue处理DOM。 // 然而为了本性能演示,我们直接操作节点 // 以匹配原生JS实现。 const handleDragStart = (e) => { const target = e.target; // 将圆形移动到拖动图层 target.moveTo(dragLayer.value.getNode()); }; const handleDragEnd = (e) => { const target = e.target; // 将圆形移回主要图层 target.moveTo(mainLayer.value.getNode()); }; </script>