关于javascript:vuegridlayout拖拽布局实现空位添加新元素

7次阅读

共计 2147 个字符,预计需要花费 6 分钟才能阅读完成。

场景

我的项目中遇到要做一个报表的仪表盘,每一个卡片内是一个报表,报表有不同类型,每一种类型有其特定的尺寸。容许抉择报表并增加到仪表盘。容许通过拖拽调整每个卡片地位和卡片的大小。最终能够保留布局好的仪表盘。

遇到的问题

vue-grid-layout 通过保护一个数组 (layout) 实现拖拽布局,每一个卡片为一个 item,每一个 item 含有坐标,宽低等信息。

因而增加卡片时向数组中增加一个 item 即可,然而这样新 item 的坐标总是(0, 0),会将曾经布局好的卡片挤走,无奈实现抉择可包容卡片的空位增加新元素。

解决思路

卡片对象有以下属性,其中 x, y, w, h 是用于记录卡片地位和大小的要害信息,i是卡片的 id,须要保障在增加时不呈现反复卡片。minWminH 用于规定卡片的最小尺寸,type用于标记该卡片的类型。

// 卡片对象
{
  "i":"card1",
  "x": 0,
  "y": 0,
  "w":4,
  "h":2,
  "minW": 3,
  "minH":2,
  "type":"typeA"
}

要实现抉择可包容该卡片的空位增加卡片,实际上就是依据现有布局(layout)和新卡片的大小(wh),算出新卡片的坐标(xy)。

可分为以下步骤:

  1. 初始化新元素:创立新卡片元素,需蕴含布局所需的所有属性,最好能继承已创立好卡片的所有其余属性。
  2. 确定布局边界:确定卡片容许增加的区域范畴
  3. 生成地图 :应用二维数组生成地图并依据layout 标记地图的占位状况
  4. 申请地位:遍历地图,依据新元素的尺寸在地图上申请地位,当有满足其大小的空位时将其插入

具体实现

<!-- grid-layout 组件调用 -->
<grid-layout
    :layout.sync="layout"
    :col-num="12"
    :row-height="72"
    :is-draggable="true"
    :is-resizable="true"
    :is-mirrored="false"
    :vertical-compact="true"
    :margin="[10, 10]"
    :autoSize="true"
    :use-css-transforms="true">
        <grid-item
            v-for="item in layout"
            :x="item.x"
            :y="item.y"
            :w="item.w"
            :h="item.h"
            :i="item.i"
            :minW="item.minW"
            :minH="item.minH"
            :key="item.i">
            <!-- 插入你的组件 -->
        </grid-item>
</grid-layout>
/* 新增元素办法 **/
function addItem(item, itemId, layout) {
  // 初始化元素
  let newItem = {
    ...item,
    "i": itemId,
    "x": 0,
    "y": 0,
    "w": item.w,
    "h": item.h
  }
  // 确定边界
  let Ys = [], maxX = 0, maxY = 0, edgeX = 0, edgeY = 0
  layout.map(item => {Ys.push(item.y + item.h)
  })
  maxY = Ys.length && Math.max.apply(null, Ys) || 1
  edgeX = 12
  edgeY = maxY
  // 应用二维数组生成地图
  let gridMap = new Array()
  for (let x = 0; x < edgeX; x++) {gridMap[x] = new Array()
    for (let y = 0; y < edgeY; y++) {gridMap[x][y] = 0
    }
  }
  // 标记占位
  layout.map(item => {
    // 将 layout 中卡片所占区域标记为 1
    for (let x = item.x; x < (item.x + item.w); x++) {for (let y = item.y; y < (item.y + item.h); y++) {gridMap[x][y] = 1
      }
    } 
  })
  // 遍历地图,申请地位
  for (let y = 0; y < edgeY; y++) {for (let x = 0; x < edgeX; x++) {
      // 申请所需空间
      if (edgeX - x >= item.w && edgeY - y >= item.h) {let itemSignArr = []
        for (let a = x; a < (x + item.w); a++) {for (let b = y; b < (y + item.h; b++)) {itemSignArr.push(gridMap[x][y])
          }
        }
        if (itemSignArr.indexOf(1) < 0) {
          newItem.x = x
          newItem.y = y
          layout.push(newItem)
          return
        }
      }
    }
  }
  // 无满足条件
  newItem.x = 0
  newItem.y = edgeY + 1
  layout.push(newItem)
}

该办法的关键在于申请空间:

在遍历地图上每一个栅格时,首先须要确定横向和纵向所剩空间是否能包容下卡片。
如果不能,间接跳出,在可布局边界的最初一行增加元素即可。
如果能够包容,考查新元素所需空间的每一个栅格是否被占用(地图 gridMap 中标记 ”1″ 位占用),这里借助一个数组 itemSignArr 记录占用状况。如果这个数组中没有呈现 ”1″,即示意所需空间是 ” 空 ” 的,能够再次插入卡片。否则进入下一个栅格反复申请过程。

相干浏览

vue-grid-layout 文档

正文完
 0