vue-grid-layout元素交换位置及大小

div元素
bash 复制代码
  <grid-layout
    :layout="map"
    :col-num="10"
    :maxRows="6"
    :row-height="rowHeight"
    :is-draggable="true"
    :is-resizable="true"
    :autoSize="false"
    :is-mirrored="false"
    :vertical-compact="true"
    :preventCollision = "false"
    :margin="[10, 10]"
    :use-css-transforms="true"
  >

    <grid-item v-for="item in map"
               :x="item.x"
               :y="item.y"
               :w="item.w"
               :h="item.h"
               :i="item.i"
               :key="item.i"
               @move="moveEvent"
               @moved="movedEvent"
               @resized="resizeEvent"
               class="gridItem">
      
      <h1 >{{item.i}}</h1>

    </grid-item>
  </grid-layout>
demo数据:
bash 复制代码
	  windowHeight: 0,
      rowHeight:130,
      layout: [
        { x: 0, y: 0, w: 3, h: 2, i: "0"},
        { x: 3, y: 0, w: 4, h: 3, i: "1" },
        { x: 7, y: 0, w: 3, h: 2, i: "2" },

        { x: 0, y: 2, w: 3, h: 2, i: "10" },
        { x: 3, y: 3, w: 4, h: 3, i: "11" },
        { x: 7, y: 2, w: 3, h: 2, i: "12" },

        { x: 0, y: 4, w: 3, h: 2, i: "20" },
        { x: 7, y: 4, w: 3, h: 2, i: "22" },
      ],
      map:[],
      curBox:'',
交换的主要方法:
bash 复制代码
	moveEvent(i, x, y) {
      this.curBox = i
    },
    
    movedEvent(i, x, y){
      //   1 根据移动位置,循环数据源当前位置是否有元素,不包含自己的位置
      if (y>11) this.map = JSON.parse(JSON.stringify(this.layout));
      const item1 = this.layout.find(
        (item) => item.x <= x && x < (item.x+item.w) && item.y <=y && (y < item.y+item.h) && item.i != i
      );
      const item2 = this.layout.find(
        (item) =>  item.i == i
      );
      // console.log(item1,item2)
      item1 && this.changePosition(item1,item2)
      if(!item1) this.layout = JSON.parse(JSON.stringify(this.map));
      localStorage.setItem("layout",JSON.stringify(this.layout))
    },
    
	changePosition(item1, item2) {
      // console.log(item1, item2);
      // 定义中间变量交换
      const temp = JSON.parse(JSON.stringify(item1));
      const temp2 = JSON.parse(JSON.stringify(item2));
      //   注意:修改的是影响显示的实际数组 map 
      this.layout.forEach((item) => {
        // 找到 item1,将 item1 的信息换成item2
        if (item.i === item1.i) {
          item.x = temp2.x;
          item.y = temp2.y;
          item.w = temp2.w
          item.h = temp2.h
        }
        if (item.i === item2.i) {
          item.x = temp.x;
          item.y = temp.y;
          item.w = temp.w;
          item.h = temp.h;
        }
      });
      // 实现交换后,及时同步 数据映射
      this.map = JSON.parse(JSON.stringify(this.layout));
    },
扩展:动态行高、echarts图表动态渲染、指定元素可拖动

动态计算行高:

bash 复制代码
 mounted() {
    if (localStorage.getItem('layout')){
      this.layout = JSON.parse(localStorage.getItem('layout'))
    }
    this.map = JSON.parse(JSON.stringify(this.layout));
    localStorage.setItem("layout",JSON.stringify(this.layout))
    this.onWindowResize()
    window.addEventListener('resize', this.onWindowResize); // 添加事件监听器
  },
  beforeDestroy() {
    window.removeEventListener('resize', this.onWindowResize); // 移除事件监听器以避免内存泄漏
  },

    onWindowResize() {
      this.windowHeight = window.innerHeight; // 更新窗口高度
      this.rowHeight = (this.windowHeight-(10*7))/6 //margin的高度*(行数+1)
    },

echarts图表动态渲染:

bash 复制代码
//div中,注意data如果是方法中有更新需重新赋值给datalist
<component :is="item.chart" :chart-date="dataList[item.i]"></component>

//实际echarts中动态更新视图内容
 	const elementResizeDetectorMaker = require("element-resize-detector");
    let erd = elementResizeDetectorMaker();
//mounted中(ref对应div绑定的ref)
        this.$nextTick(() => {
          erd.listenTo(this.$refs.radarBasic, () => {
            this.$nextTick(function () {
              //使echarts尺寸重置
              this.myChart.resize();
            });
          });
        })

指定元素可拖动:drag-ignore-from=".draggable" drag-allow-from=".itemTitle"

bash 复制代码
<grid-item v-for="item in map"
                     :x="item.x"
                     :y="item.y"
                     :w="item.w"
                     :h="item.h"
                     :i="item.i"
                     :key="item.i"
                     @move="moveEvent"
                     @moved="movedEvent"
                     @resized="resizeEvent"
                     drag-ignore-from=".draggable"
                     drag-allow-from=".itemTitle"
                     class="cardItem_dark cardItem"
          > <div class="title-top"></div>
            <div class="itemTitle centerItem">{{item.title}}</div>
           <div class="draggable" v-if="['2','4','5','7'].includes(item.i)" :style="'width:'+ 9.3*item.w+'vw;'+'height:'+ (rowHeight*item.h+20*(item.h-1.1))+'px;padding-top:5%'">
             <component :is="item.chart" :chart-date="dataList[item.i]"></component>
           </div>
            <div class="draggable" v-else :style="'width:'+ 9*item.w+'vw;'+'height:'+ (rowHeight*item.h+20*(item.h-1.1))+'px;padding-top:5px'">
             <component :is="item.chart" :chart-date="dataList[item.i]"></component>
           </div>
          </grid-item>

参考链接:
Vue Grid Layout - 适用Vue.js的栅格布局系统(项目实例)
Vue Grid Layout -️ 适用Vue.js的栅格布局系统(保姆级使用教程)
Vue Grid Layout 官方文档