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>