vue3 使用 konva

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>
相关推荐
小彭努力中1 小时前
16.在Vue3中使用Echarts实现词云图
前端·javascript·vue.js·echarts
来一碗刘肉面1 小时前
Vue - ref( ) 和 reactive( ) 响应式数据的使用
前端·javascript·vue.js
约定Da于配置7 小时前
uniapp封装websocket
前端·javascript·vue.js·websocket·网络协议·学习·uni-app
大叔_爱编程7 小时前
wx030基于springboot+vue+uniapp的养老院系统小程序
vue.js·spring boot·小程序·uni-app·毕业设计·源码·课程设计
计算机学姐9 小时前
基于微信小程序的驾校预约小程序
java·vue.js·spring boot·后端·spring·微信小程序·小程序
cafehaus11 小时前
抛弃node和vscode,如何用记事本开发出一个完整的vue前端项目
前端·vue.js·vscode
微光无限12 小时前
Vue3 中使用组合式API和依赖注入实现自定义公共方法
前端·javascript·vue.js
家里有只小肥猫13 小时前
虚拟mock
vue.js
独泪了无痕13 小时前
研究 Day.js 及其在 Vue3 和 Vue 框架中的应用详解
前端·vue.js·element
画船听雨眠aa16 小时前
vue项目创建与运行(idea)
前端·javascript·vue.js