After a day of eating and eating, the result is something like this, but it’s still not perfect. For example, my blocks are all aligned to the left, and if the previous line is short, it will merge into one line. But this is the first version I’ve worked on so far, so send it first and then continue.

<template >
  <div>
    <div ref="gridContent" class="grid_group">
      <div
        v-for="(dragData, index) in dragList"
        :key="index"
        v-drag
        class="drag-item"
        :class="classObject[index]"
        onselectstart="return false;"
      >
        <div class="drag-data-div">This is the {{dragdata.data}} data</div>
      </div>
    </div>
  </div>
</template>
<script>
import _ from "lodash";
export default {
  name: "mapStudy".directives: {
    drag: {
      bind: function (el, binding, vnode) {
        const moveEl = el;
        // console.log(el);
        moveEl.onmousedown = (event) = > {
          moveEl.style.boxShadow = "#e6e6e6 0 0 10px 10px";
          moveEl.style.zIndex = 100;
          vnode.context.dragStart(event);
          // Gets the current position of the clicked element
          const disX = event.clientX;
          const disY = event.clientY;
          vnode.context.fnMatchEvery(moveEl);
          document.onmousemove = (dEvent) = > {
            // Get the distance moved
            let x = dEvent.clientX - disX;
            let y = dEvent.clientY - disY;
            // Get the region where the current element can be moved
            const { minX, maxX, minY, maxY } = vnode.context.getRangeOfEl(
              moveEl
            );
            x = x < minX ? minX : x > maxX ? maxX : x;
            y = y < minY ? minY : y > maxY ? maxY : y;
            moveEl.style.left = x + "px";
            moveEl.style.top = y + "px";
          };
          document.onmouseup = (upEvent) = > {
            document.onmousemove = null; // The event listener needs to be cancelled
            document.onmouseup = null; // The event listener needs to be cancelled
            moveEl.style.boxShadow = "none";
            moveEl.style.zIndex = 100; vnode.context.changeBlock(moveEl); vnode.context.dragEnd(upEvent, vnode.context.dragList); }; }; }},},data() {
    return {
      column: 3.gridAreas: "".classObject: {},
      allRow: 0.oneWidth: 0.oneHeight: 0.tempData: [].dragDataList: [{type: "B".data: 1 },
        { type: "A".data: 2 },
        { type: "A".data: 3 },
        { type: "B".data: 4 },
        { type: "C".data: 5 },
        { type: "C".data: 6 },
        { type: "B".data: 7 },
        { type: "B".data: 8 },
        { type: "C".data: 9},].oldXY: { x: 0.y: 0 },
      dragList: [].tempDragList: [].type: "resort".// rearrange resort/ replace
    };
  },
  mounted: function () {
    this.dragList = _.cloneDeep(this.dragDataList);
    this.fnDisman();
    this.joinGridArea();
  },
  methods: {
    // Calculate the position of each block
    fnMatchEvery(moveEl) {
      let typeName = moveEl.className.split("") [1];
      let type =
        typeName.slice(9, typeName.length) == "A"
          ? 3
          : typeName.slice(9, typeName.length) == "B"
          ? 2
          : typeName.slice(9, typeName.length) == "C"
          ? 1
          : null;
      let oneWidth = moveEl.offsetWidth / type;
      let oneHeight = moveEl.offsetHeight;
      this.oneWidth = moveEl.offsetWidth / type;
      this.oneHeight = moveEl.offsetHeight;
      let endData = JSON.parse(JSON.stringify(this.dragList));
      let isNew = true;
      let currentRow = 0;
      let temp = 0;
      for (let i = 0; i < endData.length; i++) {
        endData[i].index = i;
        endData[i].len =
          endData[i].type == "A"
            ? 3
            : endData[i].type == "B"
            ? 2
            : endData[i].type == "C"
            ? 1
            : null;
        if (isNew) {
          endData[i].currentRow = currentRow;
          endData[i].left = 0;
          endData[i].top = currentRow * (oneHeight + 5);
          endData[i].bottom = (currentRow + 1) * oneHeight + currentRow * 5;
          endData[i].right =
            endData[i].len * oneWidth + (endData[i].len - 1) * 5;
          if (endData[i].len < 3) {
            isNew = false;
            temp = endData[i].len;
          } else {
            isNew = true;
            currentRow += 1; }}else {
          if (temp + endData[i].len <= 3) {
            endData[i].currentRow = currentRow;
            endData[i].left = temp * oneWidth;
            if (temp > 0) {
              endData[i].right =
                temp * oneWidth +
                endData[i].len * oneWidth +
                (temp - 1) * 5 +
                (endData[i].len - 1) * 5;
            } else {
              endData[i].right =
                temp * oneWidth +
                endData[i].len * oneWidth +
                (endData[i].len - 1) * 5;
            }
            endData[i].top = currentRow * (oneHeight + 5);
            endData[i].bottom = (currentRow + 1) * (oneHeight + 5);
            if (temp + endData[i].len == 3) {
              isNew = true;
              currentRow += 1;
              temp = 0;
            } else {
              isNew = false; temp = temp + endData[i].len; }}else {
            endData[i].currentRow = currentRow + 1;
            currentRow += 1;
            endData[i].left = 0;
            endData[i].right =
              endData[i].len * oneWidth + (endData[i].len - 1) * 5;
            endData[i].top = currentRow * (oneHeight + 5);
            endData[i].bottom = (currentRow + 1) * (oneHeight + 5);
            if (endData[i].len < 3) {
              isNew = false;
              temp = endData[i].len;
            } else {
              isNew = true;
              currentRow += 1; }}}}this.allRow = endData[endData.length - 1].currentRow + 1;
      this.tempData = endData;
    },
    / / the class down
    fnDisman() {
      let Obj = {};
      for (let i = 0; i < this.dragList.length; i++) {
        let str = "drag-item" + this.dragList[i].type + "" + "index" + i;
        Obj[i] = str;
      }
      this.classObject = Obj;
    },
    // Grid style splice
    joinGridArea: function () {
      // console.log(this.dragList);
      const len = this.dragList.length;
      let areaStr = "";
      for (let i = 0; i < len; i++) {
        if (i % this.column === 0) {
          areaStr += '"area-' + i + "";
          if (this.column === 1) {
            areaStr += '"'; }}else if (i % this.column === this.column - 1) {
          areaStr += "area-" + i + '"';
        } else {
          areaStr += "area-" + i + ""; }}if (len % this.column ! = =0) {
        const emptyLength = this.column - (len % this.column);
        areaStr += new Array(emptyLength).fill(".").join("") + '"';
      }
      this.gridAreas = areaStr;
    },
    dragStart: function (event) {
      this.$message({
        type: "info".message: 'Drag starts, and you can view the event parameter through the console,The ${JSON.stringify(
          event
        )}`});console.info("Start dragging", event);
    },
    dragEnd: function (event, dragList) {
      this.$message({
        type: "info".message: 'After the drag, you can view the event parameters on the console.The ${JSON.stringify(
          event
        )}.${dragList}`});console.info("End of drag.", event, dragList);
    },
    // Rearrange or replace data at the end of the drag
    changeBlock: function (moveEl) {
      // Move the cube into the corresponding area
      const { nowIndex, index } = this.getIndexOfMoveEL(moveEl);
      if (this.type === "replace") {
        const temp = this.dragList[index];
        this.$set(this.dragList, index, this.dragList[nowIndex]);
        this.$set(this.dragList, nowIndex, temp);
      } else {
        // console.log(" Finally!! ") , this.dragList);
        // console.log(this.dragList[index]);
        // console.log(this.dragList[nowIndex]);
        const temp = this.dragList[index];
        this.dragList.splice(index, 1);
        this.dragList.splice(nowIndex, 0, temp);
        this.fnDisman();
      }
      moveEl.style.left = 0;
      moveEl.style.top = 0;
    },
    // // calculates how far the current element can move
    getRangeOfEl: function (moveEl) {
      let indexName = moveEl.className.split("") [2],
        _this = this;
      let index = indexName.slice(5, indexName.length);
      let currentData = _this.tempData[index];
      const res = {};
      res.minX = -currentData.left - 10;
      res.maxX = _this.oneWidth * 3 + 5 - currentData.right;
      res.minY = -currentData.top;
      res.maxY =
        _this.allRow * _this.oneHeight - currentData.bottom + _this.allRow * 5;
      return res;
    },
    getIndexOfMoveEL: function (moveEl) {
      let allData = this.tempData,
        nowIndex = null;
      const x = parseInt(moveEl.style.left.split("px") [0]);
      const y = parseInt(moveEl.style.top.split("px") [0]);
      let indexName = moveEl.className.split("") [2],
        _this = this;
      let index = indexName.slice(5, indexName.length);
      let currentData = _this.tempData[index];
      let moveToX = (currentData.left + currentData.right) / 2 + x;
      let moveToY = (currentData.top + currentData.bottom) / 2 + y;
      if (isNaN(moveToX)) {
        nowIndex = index;
      } else {
        // Decide which line to go to first
        let row = moveToY / (this.oneHeight + 5);
        let newArr = [];
        for (let x = 0; x < allData.length; x++) {
          if (allData[x].currentRow == Math.ceil(row) - 1) { newArr.push(allData[x]); }}let currentNum = null./ / cover
          isBefore = true; // See if the slider is before or after the overlay
        for (let c = 0; c < newArr.length; c++) {
          if (moveToX < (newArr[c].left + newArr[c].right) / 2) {
            isBefore = true;
            currentNum = c;
            break;
          } else {
            isBefore = false;
            currentNum = c;
          }
        }
        isBefore
          ? (nowIndex = newArr[currentNum].index)
          : (nowIndex = newArr[currentNum].index + 1);
        if (index < nowIndex) {
          nowIndex -= 1; }}return{ nowIndex, index }; ,}}};</script>
<style lang="less" scoped>
.grid_group {
  --columnWidth: "auto";
  --rowHeight: "auto";
  display: grid;
  grid-template-columns: repeat(3.33.33%);
  grid-template-rows: auto;
  gap: 5px 5px;
  // grid-auto-flow: row dense;
  justify-content: center;
  align-content: center;
  // width: fit-content;
  width: 100%;
  position: relative;
  .drag-item {
    position: relative;
    background-color: gray;
    width: var(--columnWidth);
    height: var(--rowHeight);
    line-height: var(--rowHeight);
    text-align: center;
    user-select: none;
    .drag-data-div {
      color: #ffffff;
      width: 100px;
      height: 100px;
      line-height: 100px; }}.drag-itemA {
    grid-column: span 3;
  }
  .drag-itemB {
    grid-column: span 2;
  }
  .drag-itemC {
    grid-column: span 1; } / /.drag-item4 {
  //   grid-row: 2 / span 2; / /}}</style>
Copy the code