1:安装 npm install vue-konva konva --save
在main.ts 里面引入
import VueKonva from 'vue-konva';
app.use(VueKonva);
2:效果图
3:直接粘贴复制就能用你 (重要的地方做了备注)
<template>
<div style="display: flex; height: 100vh;">
<!-- 左侧 el-tree 树形结构 -->
<div style="width: 300px; padding: 20px; background: #f0f0f0; border-right: 2px solid #ccc;">
<h3>选择图片</h3>
<el-tree
:data="treeData"
:props="treeProps"
draggable
default-expand-all
@node-drag-start="onDragStart"
@node-drag-end="onDragEnd"
style="width: 100%;"
>
<template #default="{ node, data }">
<span>{{ data.label }}</span>
</template>
</el-tree>
</div>
<!-- 右侧 Konva 画布区域 -->
<div
ref="stageContainer"
@dragover.prevent="onDragOver"
@drop.prevent="onDrop"
style="flex: 1; height: 100%; background: #fafafa; padding: 20px; position: relative;"
>
<button @click="saveCanvas">保存</button>
<div id="konva-container" style="width: 100%; height: 100%;background:#f0f0f0;"></div>
</div>
</div>
</template>
<script>
import { onMounted, ref, nextTick } from 'vue';
import Konva from 'konva';
import { ElTree } from 'element-plus';
export default {
components: {
ElTree,
},
setup() {
const stage = ref(null);
const layer = ref(null);
const draggedNode = ref(null);
// 树形数据结构
const treeData = ref([
{
id: 1,
label: 'Lion',
src: 'https://konvajs.org/assets/lion.png',
},
]);
// 树的配置
const treeProps = {
label: 'label',
children: 'children',
};
// 初始化 Konva stage
onMounted(() => {
nextTick(() => {
// 这里的宽高,可以改成某个容器的宽高
// stageContainer.value.clientWidth
// stageContainer.value.clientHeight
stage.value = new Konva.Stage({
container: 'konva-container',
width: window.innerWidth - 350,
height: window.innerHeight,
});
layer.value = new Konva.Layer();
stage.value.add(layer.value);
// 添加右键菜单事件处理
stage.value.on('contextmenu', function (e) {
e.evt.preventDefault(); // 阻止默认的右键菜单
const clickedItem = e.target;
if (clickedItem.hasName('image')) {
console.log(clickedItem)
alert("可以做一些提示,比如是否要删除,目前右键直接删除了")
// 确认删除
// proxy.$modal.confirm('是否确认删除该设备?').then(() => {
clickedItem.destroy(); // 删除图片
// 同时删除可能存在的变换器
stage.value.find('Transformer').forEach((tr) => tr.destroy());
layer.value.draw(); // 重绘画布
// }).catch(() => {});
}
});
// 点击事件处理
stage.value.on('click', function (e) {
const clickedItem = e.target;
// 移除所有现有的变换器
stage.value.find('Transformer').forEach((tr) => tr.destroy());
// 如果点击的是图片,添加变换器
if (clickedItem.hasName('image')) {
const transformer = new Konva.Transformer({
nodes: [clickedItem],
boundBoxFunc: (oldBox, newBox) => {
// 限制缩放和移动范围
if (newBox.width < 50 || newBox.height < 50) {
return oldBox;
}
return newBox;
}
});
layer.value.add(transformer);
}
layer.value.draw();
});
});
});
// 拖拽开始时记录节点信息
const onDragStart = (event, nodeData) => {
draggedNode.value = nodeData;
};
// 拖拽结束
const onDragEnd = () => {
draggedNode.value = null;
};
// 拖拽悬停处理
const onDragOver = (event) => {
event.preventDefault();
};
// 拖放处理
const onDrop = (event) => {
event.preventDefault();
if (draggedNode.value) {
// 获取相对于 Konva 容器的准确坐标
const container = document.getElementById('konva-container');
const containerRect = container.getBoundingClientRect();
// 这里减50是因为宽是100,减去50为了让图片在鼠标中间
// 高同理
const x = event.clientX - containerRect.left-50;
const y = event.clientY - containerRect.top-50;
addImageToCanvas("https://konvajs.org/assets/lion.png", x, y);
}
};
// 将图片添加到 Konva 画布
const addImageToCanvas = (imageUrl, x, y) => {
const imageObj = new Image();
imageObj.src = imageUrl;
imageObj.onload = () => {
const konvaImage = new Konva.Image({
image: imageObj,
x: x,
y: y,
// 自定义字段
attrs: { device: "2", adad: "2131", yrr: "2313" },
// 默认的宽高
width: 100,
height: 100,
draggable: true,
name: 'image',
dragBoundFunc: function(pos) {
const container = stage.value.container();
const containerRect = container.getBoundingClientRect();
const minX = 0;
const minY = 0;
const maxX = containerRect.width - 100; // 减去默认设置的宽
const maxY = containerRect.height - 100; // 减去默认设置的高
return {
x: Math.max(minX, Math.min(pos.x, maxX)),
y: Math.max(minY, Math.min(pos.y, maxY))
};
}
});
layer.value.add(konvaImage);
layer.value.draw();
};
};
const saveCanvas =async () => {
if (!stage.value) return;
const images = layer.value.find('Image');
const layoutData = images.map(image => {
return {
pointx: image.x(),
pointy: image.y(),
width: image.scaleX() * image.width(),
height: image.scaleY() * image.height(),
rotation: image.rotation()
};
});
console.log(layoutData)
try {
alert('保存成功');
} catch (error) {
alert('保存失败');
}
};
return {
treeData,
treeProps,
onDragStart,
onDragEnd,
onDragOver,
onDrop,
saveCanvas
};
},
};
</script>
<style scoped>
#konva-container {
border: 2px dashed #ccc;
}
</style>