zoukankan      html  css  js  c++  java
  • vue-grid-layout拖拽布局实现空位添加新元素

    场景

    项目中遇到要做一个报表的仪表盘,每一个卡片内是一个报表,报表有不同类型,每一种类型有其特定的尺寸。允许选择报表并添加到仪表盘。允许通过拖拽调整每个卡片位置和卡片的大小。最终可以保存布局好的仪表盘。

    遇到的问题

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

    因此添加卡片时向数组中添加一个item即可,但是这样新item的坐标总是(0, 0),会将已经布局好的卡片挤走,无法实现选择可容纳卡片的空位添加新元素。

    解决思路

    卡片对象有以下属性,其中x, y, w, h是用于记录卡片位置和大小的关键信息,i是卡片的id,需要保证在添加时不出现重复卡片。minW和minH用于规定卡片的最小尺寸,type用于标记该卡片的类型。

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

    要实现选择可容纳该卡片的空位添加卡片,实际上就是根据现有布局(layout)和新卡片的大小(w和h),算出新卡片的坐标(x和y)。

    可分为以下步骤:

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

    vi设计http://www.maiqicn.com 办公资源网站大全https://www.wode007.com

    具体实现

    <!-- 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",即表示所需空间是"空"的,可以再次插入卡片。否则进入下一个栅格重复申请过程。

  • 相关阅读:
    trident介绍
    Effective TensorFlow Chapter 4: TensorFlow中的广播Broadcast机制【转】
    tslib移植笔记(1)【转】
    jz2440-linux3.4.2-kernel移植【学习笔记】【原创】
    Linxu内核版本号后面多出字符串或者+号【学习笔记】
    向linux内核版本号添加字符/为何有时会自动添加"+"号或者"xxx-dirty"【转】
    chrome浏览器新建标签打开页面【学习笔记】
    jz2440-uboot-201204版本移植【学习笔记】【原创】
    Ubuntu 14.04 下安装 TFTP 艰辛之路【转】
    更改UBoot实现通过loady命令下载代码【转】
  • 原文地址:https://www.cnblogs.com/xiaonian8/p/13705787.html
Copyright © 2011-2022 走看看