HTML5 Canvas 如何避免内存泄漏提示
删除形状
有两种非常相似的方法 remove()
和 destroy()
。如果你需要完全删除一个节点,你应该使用 destroy()
。destroy()
方法会删除 KonvaJS 引擎中对节点的所有引用。如果你打算再次使用该节点,你可以先使用 remove()
,然 后你可以将其添加回任何容器。
动画过渡
当你使用 Konva.Tween
实例时,你必须在使用后将其销毁。
以下是一个关于正确内存管理的演示:
- 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); // 创建圆形 const circle = new Konva.Circle({ x: 100, y: 100, radius: 30, fill: 'red' }); layer.add(circle); // 添加按钮 const addButton = document.createElement('button'); addButton.textContent = '添加圆形'; document.body.appendChild(addButton); const removeButton = document.createElement('button'); removeButton.textContent = '移除圆形'; document.body.appendChild(removeButton); const animateButton = document.createElement('button'); animateButton.textContent = '动画'; document.body.appendChild(animateButton); // 处理添加/移除 addButton.addEventListener('click', () => { layer.add(circle); }); removeButton.addEventListener('click', () => { // 只是从图层中移除,可以再添加回去 circle.remove(); }); animateButton.addEventListener('click', () => { // 使用 to() 方法,该方法会自动销毁动画 circle.to({ x: Math.random() * stage.width(), y: Math.random() * stage.height(), duration: 1 }); // 如 果直接使用 Tween,请确保销毁它 const tween = new Konva.Tween({ node: circle, rotation: 360, duration: 1, onFinish: function() { // 清理动画 tween.destroy(); } }).play(); });
import { Stage, Layer, Circle } from 'react-konva'; import { useState } from 'react'; const App = () => { const [isVisible, setIsVisible] = useState(true); const [position, setPosition] = useState({ x: 100, y: 100 }); const [rotation, setRotation] = useState(0); const handleAdd = () => { setIsVisible(true); }; const handleRemove = () => { setIsVisible(false); }; const handleAnimate = () => { // 更新位置 setPosition({ x: Math.random() * window.innerWidth, y: Math.random() * window.innerHeight }); // 更新旋转角度 setRotation(rotation + 360); }; return ( <div> <button onClick={handleAdd} style={{ marginRight: '10px' }}>添加圆形</button> <button onClick={handleRemove} style={{ marginRight: '10px' }}>移除圆形</button> <button onClick={handleAnimate}>动画</button> <Stage width={window.innerWidth} height={window.innerHeight}> <Layer> {isVisible && ( <Circle x={position.x} y={position.y} radius={30} fill="red" rotation={rotation} /> )} </Layer> </Stage> </div> ); }; export default App;
<template> <div> <button @click="handleAdd" style="margin-right: 10px">添加圆形</button> <button @click="handleRemove" style="margin-right: 10px">移除圆形</button> <button @click="handleAnimate">动画</button> <v-stage :config="stageSize"> <v-layer> <v-circle v-if="isVisible" :config="circleConfig" /> </v-layer> </v-stage> </div> </template> <script setup> import { ref } from 'vue'; const stageSize = { width: window.innerWidth, height: window.innerHeight }; const isVisible = ref(true); const position = ref({ x: 100, y: 100 }); const rotation = ref(0); const circleConfig = ref({ x: position.value.x, y: position.value.y, radius: 30, fill: 'red', rotation: rotation.value }); const handleAdd = () => { isVisible.value = true; }; const handleRemove = () => { isVisible.value = false; }; const handleAnimate = () => { // 更新位置 position.value = { x: Math.random() * window.innerWidth, y: Math.random() * window.innerHeight }; // 更新旋转角度 rotation.value += 360; // 更新配置 circleConfig.value = { ...circleConfig.value, x: position.value.x, y: position.value.y, rotation: rotation.value }; }; </script>