在使用draggable的时候遇到了一些问题 好在最终解决了 记录下希望能帮助到有缘人
页面功能 可实现模块的放大缩小以及位置的更换 同时echarts会跟着父元素大小而变化,有兴趣者自己研究吧 代码放在下面了 直接cv就好 不难 但是有些细节要注意 比如draggable需要绑定唯一的key值否则改变元素样式时会出问题 以及echarts跟随父盒子自适应需要在echarts中配置grid属性并结合window的监听事件去实现
<template> <div class="itxst"> <div class="group"> <draggable v-model="group" ghost-class="ghost" handle=".move" filter=".forbid" :force-fallback="true" chosen-class="chosenClass" animation="300" @start="onStart" @end="onEnd" group="group1" :fallback-class="true" :fallback-on-body="true" :touch-start-threshold="50" :fallback-tolerance="50" :move="onMove" class="draggablesty" item-key="id" > <template #item="{ element }"> <div :class="element.disabledMove ? 'forbid item' : 'item'" :key="element.id" > <label class="move">{{ element.name }}</label> <div class="echarts" :ref="setItemRef"></div> <span class="icon" @mousedown="mouseScale"></span> </div> </template> </draggable> </div> </div> </template> <script setup> import { reactive, toRefs, onMounted } from "vue"; import * as echarts from "echarts"; //导入draggable组件 import draggable from "vuedraggable"; const state = reactive({ /*工作台的数据结构 disabledMove:禁止移动 disabledPark:禁止停靠 */ group: [ { name: "消息", id: 1, disabledMove: false, disabledPark: false, refVal: "ref1", }, { name: "库存", id: 2, disabledMove: false, disabledPark: false, refVal: "ref2", }, { name: "销量", id: 3, disabledMove: false, disabledPark: false, refVal: "ref3", }, { name: "日志", id: 4, disabledMove: false, disabledPark: false, refVal: "ref4", }, ], }); const { group } = toRefs(state); let itemRefs = []; const setItemRef = (el) => { if (el) { itemRefs.push(el); } }; //拖拽开始的事件 const onStart = (e) => { console.log("开始拖拽"); }; //拖拽结束的事件 const onEnd = (e) => { console.log("结束拖拽"); }; const mouseScale = (ev) => { // 子节点 let target = ev.target; // 父节点 let parent = ev.target.parentNode; let myEvent = ev; var distanceX = myEvent.clientX - parent.offsetWidth; var distanceY = myEvent.clientY - parent.offsetHeight; document.onmousemove = function (ev) { var myEvent = ev; parent.style.width = myEvent.clientX - distanceX + target.offsetWidth + "px"; parent.style.height = myEvent.clientY - distanceY + target.offsetHeight + "px"; }; document.onmouseup = function () { document.onmousemove = null; document.onmouseup = null; }; }; const myECharts = () => { let myChart = echarts.init(itemRefs[0]); // 基于准备好的dom,初始化echarts实例 // 绘制图表 myChart.setOption({ title: { text: "ECharts 入门示例", x: "center", }, tooltip: {}, xAxis: { data: ["衬衫", "羊毛衫", "雪纺衫", "裤子", "高跟鞋", "袜子"], }, yAxis: {}, grid: { top: 35, left: 55, right: 45, bottom: 20, width: "auto", height: "auto", }, series: [ { name: "销量", type: "bar", data: [5, 20, 36, 10, 10, 20], }, ], }); window.addEventListener("resize", function () { myChart.resize(); }); window.addEventListener("mousemove", function () { myChart.resize(); }); }; const onMove = (e, originalEvent) => { //不允许停靠 if (e.relatedContext.element.disabledPark == true) return false; return true; }; onMounted(() => { myECharts(); }); </script> <style> body { padding: 0px; margin: 0px; background-color: #f1f1f1; } .itxst { background-color: #f1f1f1; display: flex; padding: 20px; width: 100%; } .group { width: 100%; height: 100%; } .draggablesty { display: flex; flex-wrap: wrap; width: 100%; height: 100%; } .item { border: solid 1px #ddd; padding: 0px; text-align: left; background-color: #fff; margin-bottom: 10px; display: flex; flex-direction: column; user-select: none; width: 48%; height: 250px; margin: 1%; position: relative; } .echarts { width: 100%; height: 80%; } .icon { position: absolute; right: 0; bottom: 0; border-right: 5px solid aquamarine; border-bottom: 5px solid aquamarine; border-top: 5px solid transparent; border-left: 5px solid transparent; cursor: nw-resize; } .item > label { border-bottom: solid 1px #ddd; padding: 6px 10px; color: #333; } .item > label:hover { cursor: move; } .item > p { padding: 6px 10px; color: #666; } .ghost { border: solid 1px rgb(19, 41, 239) !important; } .chosenClass { opacity: 1; border: solid 1px red; } .fallbackClass { background-color: aquamarine; } </style>
复制