使用vue-grid-layout完成桌面拖拽布局功能

最近在用写公司项目里的一个桌面布局功能 需要使用到vue-grid-layout
看了下网上的 基本上只有demo的使用,这个插件虽然挺不错但是缺陷也很大.
没有下边界,发生碰撞的时候块会无限的往下移动
https://github.com/jbaysoluti...
先撸一遍demo吧

<template>
  <grid-layout
    :layout="layout"
    :auto-size="false"
    :col-num="20"
    :row-height="50"
    :max-rows="100"
    :is-draggable="true"
    :is-resizable="false"
    :vertical-compact="false"
    :margin="[10, 10]"
    :use-css-transforms="true"
  >

    <grid-item v-for="item in layout" :key="item.i"
               :x="item.x"
               :y="item.y"
               :w="item.w"
               :h="item.h"
               :i="item.i"
               @resize="resizeEvent"
               @move="moveEvent"
               @resized="resizedEvent"
               @moved="movedEvent"
    >
      {{item.i}}
    </grid-item>
  </grid-layout>
</template>

<script>
  import Vue from 'vue'
  import VueGridLayout from 'vue-grid-layout'
  Vue.use(VueGridLayout)

  var testLayout = [
    {"x":0,"y":0,"w":1,"h":1,"i":"0"},
    {"x":0,"y":1,"w":1,"h":1,"i":"1"},
    {"x":0,"y":2,"w":1,"h":1,"i":"2"},
    {"x":0,"y":3,"w":1,"h":1,"i":"3"},
    {"x":1,"y":0,"w":1,"h":1,"i":"4"},
    {"x":1,"y":1,"w":1,"h":1,"i":"5"},
    {"x":1,"y":2,"w":1,"h":1,"i":"6"},
    {"x":1,"y":3,"w":1,"h":1,"i":"7"},
    {"x":2,"y":0,"w":1,"h":1,"i":"8"},
    {"x":2,"y":1,"w":1,"h":1,"i":"9"},
    {"x":2,"y":2,"w":1,"h":1,"i":"10"},
    {"x":2,"y":3,"w":1,"h":1,"i":"11"},
    {"x":3,"y":0,"w":1,"h":1,"i":"12"},
    {"x":3,"y":1,"w":1,"h":1,"i":"13"},
    {"x":3,"y":2,"w":1,"h":1,"i":"14"},
    {"x":3,"y":3,"w":1,"h":1,"i":"15"},
    {"x":4,"y":0,"w":1,"h":1,"i":"16"},
    {"x":4,"y":1,"w":1,"h":1,"i":"17"},
    {"x":4,"y":2,"w":1,"h":1,"i":"18"},
    {"x":4,"y":3,"w":1,"h":1,"i":"19"}
  ];

  var GridLayout = VueGridLayout.GridLayout;
  var GridItem = VueGridLayout.GridItem;

  export default {
    name: 'Layout',
    components: {
      GridLayout,
      GridItem,
    },
    data () {
      return {
        layout: testLayout,
        newX:0,
        newY:0
      }
    },
    mounted () {

    },
    methods:{
      moveEvent: function(i, newX, newY,e){
        //console.log(e)
        //console.log("MOVE i=" + i + ", X=" + newX + ", Y=" + newY);
      },
      resizeEvent: function(i, newH, newW){
        //console.log("RESIZE i=" + i + ", H=" + newH + ", W=" + newW);
      },
      movedEvent: function(i, newX, newY,e){
        //console.log(e)
        //console.log("MOVED i=" + i + ", X=" + newX + ", Y=" + newY);
      },
      resizedEvent: function(i, newH, newW, newHPx, newWPx){
        //console.log("RESIZED i=" + i + ", H=" + newH + ", W=" + newW + ", H(px)=" + newHPx + ", W(px)=" + newWPx);
      }
    }

  }
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
  .vue-grid-layout {
     position: relative;
     width:800px;
     height:450px;
     /*overflow: hidden;*/
     background: url('../../assets/desktop_background.png') no-repeat;
  }
  .vue-grid-layout>div {
     position: absolute;
     background: indianred;
  }
</style>

随便写点样式 页面大概是这样
图片描述
options里的

  • vertical-compact 是 垂直紧凑布局 就是拖动留空了 若下方有块会自动往上补
  • use-css-transforms 是否使用css的transforms来排版 一般默认就好了 为true时是最终页面是这样的

图片描述
如果是否的话是使用绝对布局来排版的 和使用transforms排版有一点区别

看下函数

      moveEvent: function(i, newX, newY,e){
        //console.log("MOVE i=" + i + ", X=" + newX + ", Y=" + newY);
      },
      resizeEvent: function(i, newH, newW){
        //console.log("RESIZE i=" + i + ", H=" + newH + ", W=" + newW);
      },
      movedEvent: function(i, newX, newY,e){
        //console.log("MOVED i=" + i + ", X=" + newX + ", Y=" + newY);
      },
      resizedEvent: function(i, newH, newW, newHPx, newWPx){
        //console.log("RESIZED i=" + i + ", H=" + newH + ", W=" + newW + ", H(px)=" + newHPx + ", W(px)=" + newWPx);
      }

现在用到的是moveEvent和movedEvent 一个是移动时就触发 一个是移动完成 松开鼠标的时候触发
可以通过这两个事件中的i用来搞事情

敲黑板划重点

修改下grid-item里 增加watchitem

    <grid-item v-for="item in layout" :key="item.i"
               :item="watchitem(item)"
               :x="item.x"
               :y="item.y"
               :w="item.w"
               :h="item.h"
               :i="item.i"
               @resize="resizeEvent"
               @move="moveEvent"
               @resized="resizedEvent"
               @moved="movedEvent"
    >
      {{item.i}}
    </grid-item>

在methods 里增加 watchitem

    watchitem:function(item) {
        if(item.y>y_max ||item.x>x_max){
            item.y=
            item.x=
        }
        return item
    }

这边通过移动完后快速遍历每一个item的信息来修改后 达到自己所需的效果

现在的效果是当你移动一个box时 即使你没松开鼠标 每一个被你移动中碰撞到的box都会发生改变 这可能不是我们想要的 可以创建一个historyLayout 拿来记录我们上一步的布局 我们在watchitem()里比较 如果不是当前操作的box 使其的位置保持不变,在moved()中调用一个调整位置的函数 使其可以达到 两两调换的效果 以及其他的移动效果 想了解的可以点击这里

还有一个比较需要注意的是针对对象的操作会比较多 对其操作时需要注意 更改的是本身的值还是引用值

最后大概实现成这样 有能力的大神还是自己写一套比较好
图片描述

阅读 22.8k

推荐阅读
且学且珍惜
用户专栏

.

0 人关注
10 篇文章
专栏主页