vue-grid-layout拖拽布局实现空位添加新元素

时间: 2020-05-24阅读: 96标签: 拖拽

场景

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


遇到的问题

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. 申请位置:遍历地图,根据新元素的尺寸在地图上申请位置,当有满足其大小的空位时将其插入


具体实现

<!-- 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文档


站长推荐

1.云服务推荐: 国内主流云服务商,各类云产品的最新活动,优惠券领取。地址:阿里云腾讯云华为云

2.广告联盟: 整理了目前主流的广告联盟平台,如果你有流量,可以作为参考选择适合你的平台点击进入

链接: http://www.fly63.com/article/detial/9495

关闭

js实现本地图片文件拖拽效果

如何拖拽图片到指定位置,具体方法如下,在从本地上传图片的时候,如果使用拖拽效果,想想应该是更加的高大上,下面直接上js代码

实现平滑过渡的拖拽排序

最近重读Vue官方文档,在列表的排序过渡这一小节,文档提到,<transition-group> 组件有一个特殊的地方,不仅可以实现进入和离开动画,还可以改变定位,官网示例如下

原生js实现拖拽与拖放事件,JavaScript实现元素拖拽、图片到指定区域进行预览的例子

拖拽,拖放事件可以通过拖拽实现数据传递,达到良好的交互效果,如:从操作系统拖拽文件实现文件选择,拖拽实现元素布局的修改。原生Js实现元素拖拽、图片到指定区域进行预览的方法实现

原生js实现拖拽功能

如果要设置物体拖拽,必须使用三个事件,分别是:1、onmousedown:鼠标按下事件2、onmousemove:鼠标移动事件3、onmouseup:鼠标抬开事件

实现元素拖拽的两种方式

为将要拖拽的元素设置允许拖拽,并赋予dragstart事件将其id转换成数据保存;为容器添加dragover属性添加事件阻止浏览器默认事件,允许元素放置,并赋予drop事件进行元素的放置。

Vue自定义指令:通过Vue.directive实现集成第三方插件,拖拽功能,图片加载等功能

当我们需要对Dom元素进行底层操作的时候,这时候我们就需要使用vue的自定义指令。这篇文章将讲解:如何注册Vue自定义指令?Vue的钩子函数,vue钩子函数参数,vue实现拖拽功能,实现图片加载功能,Vue自定义指令集成第三方插件 ...

vue元素拖拽、移动

使用范围:两个元素位置交换,移动元素到指定位置,另外如需有需监听元素的拖拽情况,可调用对应的函数即可。如果不允许拖动到该元素区域内,可在dragover、dragenter中设置dropEffect:none;禁止拖拽。

JS 仿头条App频道编辑功能 (拖拽排序,添加,删减)

由于,项目中使用App混合开发,要实现频道编辑功能;在没找到合适的解决方案的情况下,自己写了这个库;已经在项目中跑了2年多,有不错的可用性;写下这篇文章分享下

js中drag拖拽

在没有drag事件的时候,做元素拖拽使用的都是mouse事件,但mouse在处理过程中可能有这样或那样的问题,主要还是感觉不流畅,如果小伙伴们不在考虑低版本IE(<IE9)的话,可以偿试一下drag,会有意想不到的收获。。

ngDraggable.js_AngularJS之拖拽排序

ngDraggable.js是一款比较简单实用的angularJS拖拽插件,借助于封装好的一些自定义指令,能够快速的进行一些拖拽应用开发。首先先介绍一些基本的概念;ng-drop:是否允许放入拖拽元素

点击更多...

内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!

文章投稿关于web前端网站点搜索站长推荐网站地图站长QQ:522607023

小程序专栏: 土味情话心理测试脑筋急转弯幽默笑话段子句子语录成语大全运营推广