10

相信有不同志已经使用过vue-grid-layout这个插件了,对于界面化拖拽布局操作起来还是非常友好的

前几天看到一个项目,要在此基础上优先添加到空白位置。

vue-grid-layout插件本身可以通过对数组数据的push,进行添加数据,但必要的 x , y , w , h , i 是必须的。

当然,你可以对 x 和 y 强行赋 0 , 他为将此区域内的基本项顺序往下挤。可我想我的是有空缺且能够放下时,优先使用空缺位置,没有空缺时,从上住下顺序添加。

<template>
  <div id="gridPage">
    <h1>grid</h1>
    <div class="btnGroup">
      <button @click="addItem">add</button>
    </div>
    <div class="view">
      <grid-layout
        :layout.sync="layout"
        :col-num="layoutColNum"
        :row-height="10"
        :is-draggable="true"
        :is-resizable="true"
        :is-mirrored="false"
        :vertical-compact="true"
        :margin="[10, 10]"
        :use-css-transforms="true"
        @layout-updated="layoutUpdatedEvent"
        @layout-ready="layoutReadyEvent"
        >
        <grid-item v-for="(item,idx) in layout"
          class="item"
          :x="item.x"
          :y="item.y"
          :w="item.w"
          :h="item.h"
          :i="item.i"
          :key="idx">
            {{item.i}}|{{idx}}
        </grid-item>
      </grid-layout>
    </div>
  </div>
</template>
<style lang="less">
  #gridPage{
    >h1{
      font-size: 16px;
    }
    >.view{
      border: 1px solid #000;
      .item{
        background-color: #aaa;
      }
    }
  }
</style>
<script>
import VueGridLayout from 'vue-grid-layout';

export default {
  name: 'girdPage',
  data: function (){
    return {
      // 布局位置数据
      layout: [],
      // 布局二维数组地图
      layoutMap: [],
      // 布局列数
      layoutColNum: 50
    }
  },
  methods: {
    // 添加项目
    addItem: function () {
      // 产生随机宽高
      var itemW = this.rnd(5,10);
      var itemH = this.rnd(5,10);
      var addItem = {
        "x": 0,
        "y": this.layoutMap.length,
        "w": itemW,
        "h": itemH,
        "i": this.layout[this.layout.length-1]?parseInt(this.layout[this.layout.length-1].i)+1:0
      };
      if(this.layoutMap.length){
        // console.log(this.layoutMap.length);
        for(let r = 0 , rLen =this.layoutMap.length ; r < rLen; r++){
          for(let c = 0; c <= (this.layoutColNum-itemW); c++){
            let res = this.regionalTest(
              c, 
              r, 
              itemW, 
              rLen>(r+itemH)?itemH:rLen-r
              );

            if(res.result){
              // 更新添加数据内容
              addItem = {
                "x": res.x,
                "y": res.y,
                "w": itemW,
                "h": itemH,
                "i": parseInt(this.layout[this.layout.length-1].i)+1
              };

              c = this.layoutColNum+1;
              r = rLen+1;
            }else{
              c = res.offsetX;
            }
          }
        }
      }
      // 更新二维数组地图
      for(let itemR = 0 ; itemR < itemH ; itemR++){
        for(let itemC = 0 ; itemC < itemW ; itemC++){
          // 如果没有该行,初始化
          if(!this.layoutMap[addItem.y+itemR]){
            this.layoutMap[addItem.y+itemR] = new Array(this.layoutColNum);
            for(let i = 0 ;i < this.layoutColNum ; i++){
              this.layoutMap[addItem.y+itemR][i] = 0;
            }
          }
          // 标记点
          this.layoutMap[addItem.y+itemR][addItem.x+itemC] = 1;
        }
      }
      
      // console.log(this.layoutMap);
      // 添加数据
      this.layout.push(addItem);

    },
    // 生成二维数组地图
    genereatePlaneArr: function (data) {
      var map = [];
      if(Array.isArray(data)){
        for(var i = 0; i<data.length; i ++){
          var one = data[i];
          // 循环行
          for(var r = one.y ; r < ( one.y + one.h ) ; r++){
            // 循环列
            for(var c = one.x ; c < ( one.x + one.w) ; c++){
              // 检修当前行是否存在 
              if(!map[r]){
                map[r] = new Array(this.layoutColNum);
                
                for(let i = 0 ; i < this.layoutColNum ; i++){
                  map[r][i] = 0;
                }
              }
              // 占据为1
              map[r][c] = 1;
            }
          }
        }
      }
      return map;
    },
    // 区域检测 x,y 二维数据地图起始坐标点  w,h 检测区域宽高
    regionalTest: function (x,y,w,h) {
      // 定义返回 x,y 偏移 及 是否有空位置
      let offsetX = 0,offsetY = 0,res = true;
      // 按区域循环检测 二维数组地图
      for(let r = 0; r < w ;r++){
        for(let c = 0; c <= h ;c++){
          let point = this.layoutMap[y+r]?this.layoutMap[y+r][x+c]:0;
          // 如该点被占据 记录偏移值
          if(point===1){
            res = false;
            offsetX = offsetX>(x+c)?offsetX:x+c;
            offsetY = offsetY>(y+r)?offsetY:y+r;
          }
        }
      }

      return {
        result: res,
        offsetX: offsetX,
        x: x,
        y: y
      };
    },
    // 组件更新完成生命周期
    layoutReadyEvent: function(newLayout) {
      // console.log("4Ready");
      // console.log(this.layout);
      // 当插件加载完成后  获取现在的二维地图树
      this.layoutMap = this.genereatePlaneArr(this.layout);
    },
    layoutUpdatedEvent: function(newLayout) {
      // console.log("Updated");
      // console.log(this.layout);
      // 当插件内容布局发生变化后  获取现在的二维地图树
      this.layoutMap = this.genereatePlaneArr(this.layout);
    },
    rnd: function (m,n) {
      return (Math.random()*(m-n+1)+n)|0;
    }
  },
  components: {
    GridLayout: VueGridLayout.GridLayout,
    GridItem: VueGridLayout.GridItem
  }
}

简单写的一个Demo, 不足之处还望指正


半面火焰
108 声望8 粉丝

无惧无畏,勇往直前~!