注入依赖
npm install --save vue-grid-layout
页面内容
<-- 这里走个for循环就可以当做需要的拖拽组件区域 --> <div @drag="drag" @dragend="dragend" class="droppable-element" draggable="true" unselectable="on"><img style="100%;height:100%" src="@/utils/11111.jpg"></div> <-- 拖拽搭建页面 --> <div id="content"> <grid-layout ref="gridlayout" :layout.sync="layout" :col-num="12" :row-height="30" :is-draggable="true" :is-resizable="false" :vertical-compact="true" :use-css-transforms="true" > <grid-item :key="item.i" v-for="item in layout" :x="item.x" :y="item.y" :w="item.w" :h="item.h" :i="item.i" > <img :src="item.ims" style="100%;height:100%"> <span class="text">{{ item.i }}</span> </grid-item> </grid-layout> </div>
js事件(引入依赖)
import VueGridLayout from 'vue-grid-layout'
const GridLayout = VueGridLayout.GridLayout
const GridItem = VueGridLayout.GridItem
let mouseXY = {"x": null, "y": null};
let DragPos = {"x": null, "y": null, "w": 1, "h": 1, "i": null};
js事件(参数)
export default {
components: {
GridLayout,
GridItem
},
data() {
return {
layout: [
{"x":0,"y":0,"w":2,"h":2,"i":"0"},
{"x":2,"y":0,"w":2,"h":4,"i":"1"},
{"x":4,"y":0,"w":2,"h":5,"i":"2"},
{"x":6,"y":0,"w":2,"h":3,"i":"3"},
],
};
},
}
js事件(事件功能)
drag(res){ let parentRect = document.getElementById('content').getBoundingClientRect(); let mouseInGrid = false; // 拖拽的位置发生变化 if (((mouseXY.x > parentRect.left) && (mouseXY.x < parentRect.right)) && ((mouseXY.y > parentRect.top) && (mouseXY.y < parentRect.bottom))) { // 打开创建 mouseInGrid = true; } // 确认创建后判断是否有新创建的东西 if (mouseInGrid === true && (this.layout.findIndex(item => item.i === 'drop')) === -1) { console.log('创建添加') this.layout.push({ x: (this.layout.length * 2) % (this.colNum || 12), y: this.layout.length + (this.colNum || 12), // puts it at the bottom w: 2, h: 3, i: 'drop', }); } // 查找是否有新创建的东西 let index = this.layout.findIndex(item => item.i === 'drop'); // 判断如果没有新创建的 if (index !== -1) { try { // gridlayout元素下最后一个盒子的样式隐藏 this.$refs.gridlayout.$children[this.layout.length].$refs.item.style.display = "none"; } catch { } // gridlayout元素下新添加的盒子 let el = this.$refs.gridlayout.$children[index]; // 新盒子的位置 el.dragging = {"top": mouseXY.y - parentRect.top, "left": mouseXY.x - parentRect.left}; // 新盒子的位置计算 let new_pos = el.calcXY(mouseXY.y - parentRect.top, mouseXY.x - parentRect.left); // 新创的阴影位置 if (mouseInGrid === true) { // 移动的位置(后面的两个值更改阴影大小) this.$refs.gridlayout.dragEvent('dragstart', 'drop', new_pos.x, new_pos.y, 2, 2); console.log(this.layout[index].x,111111) DragPos.i = String(index); DragPos.x = this.layout[index].x; DragPos.y = this.layout[index].y; } // 有过的盒子 if (mouseInGrid === false) { console.log(2222) // 移动位置 this.$refs.gridlayout.dragEvent('dragend', 'drop', new_pos.x, new_pos.y, 1, 1); // 数组检测输出没有drop的 this.layout = this.layout.filter(obj => obj.i !== 'drop'); } } }, dragend(res){ console.log(res,"dragend") let parentRect = document.getElementById('content').getBoundingClientRect(); let mouseInGrid = false; if (((mouseXY.x > parentRect.left) && (mouseXY.x < parentRect.right)) && ((mouseXY.y > parentRect.top) && (mouseXY.y < parentRect.bottom))) { mouseInGrid = true; } if (mouseInGrid === true) { // this.$refs.gridlayout.dragEvent('dragend', 'drop', DragPos.x, DragPos.y, 1, 1);
// 添加盒子
this.layout = this.layout.filter(obj => obj.i !== 'drop'); this.layout.push({ x: DragPos.x, y: DragPos.y, w: 2, h: 2, i: DragPos.i, ims:'https://img1.baidu.com/it/u=1228507199,1542939359&fm=26&fmt=auto&gp=0.jpg' }); // this.$refs.gridLayout.dragEvent('dragend', DragPos.i, DragPos.x,DragPos.y,1,1); } },
参数了解
<grid-layout // 作用 数据类型 必填 备注 //=================================================== // 网格初始化布局 数组 必填 每一项都必须具有i、x、y、w和h属性 属性用作什么 见下方 :layout.sync="layout" // 表示网格有多少列 数字 非必填 默认为12 :col-num="12" // 表示一行的高度(以像素为单位) 数字 非必填 默认值为150 :row-height="30" // 表示网格中最大行数 数字 非必填 默认为无穷大 :maxRows="20" // 表示网格项数是否可以拖动 Boolean 非必填 默认为true :is-draggable="true" // 表示网格是否可以改变带大小 Boolean 非必填 默认为true :is-resizable="true" // RTL/LTR 的转换 Boolean 非必填 默认为false :is-mirrored="false" // 容器是否适应内部变化 Boolean 非必填 默认为 true :autoSize="ture" // 垂直方向上 是否应该紧凑布局 Boolean 非必填 默认为true :vertical-compact="true" // 网格之间的边距 两个数字组成的数组 第一个数字为水品距离 第二个为垂直距离 非必填 默认值为 [10,10] :margin="[10, 10]" // 是否使用css的transforms来排版 非必填 为false时 使用后采用定位方式来布局 默认为true :use-css-transforms="true" // 布局是否应响应窗口宽度 非必填 默认false 为true时 会出现一些布局错乱的问题 :responsive="false" //布局是否应响应为响应布局定义的窗口宽度断点 对象类型 非必填 默认值 // { lg: 1200, md: 996, sm: 768, xs: 480, xxs: 0 } :breakpoints=" { lg: 1200, md: 996, sm: 768, xs: 480, xxs: 0 }" // 定义每个断点的列数 :cols="{ lg: 12, md: 10, sm: 6, xs: 4, xxs: 2 }" // 生命周期 @layout-created="layoutCreatedEvent" // 布局创建事件 @layout-before-mount="layoutBeforeMountEvent" // 布局安装以前事件 @layout-mounted="layoutMountedEvent" // 布局安装事件 @layout-ready="layoutReadyEvent" // 布局准备活动 @layout-updated="layoutUpdatedEvent" // 格子位置 大小更新 > // 每个单独控制 需要注意的是 每一个属性都要在data中注册一下 不然会导致不能拖拽 或者 不能放大缩小 <grid-item class="echarts_box" :x="layoutData[0].x" // 横向距离 :y="layoutData[0].y" // 纵向距离 :w="layoutData[0].w" // 宽度 :h="layoutData[0].h" // 高度 :i="layoutData[0].i" // 唯一值 (重复时设置会导致一块放大或缩小)string类型 @resize="resizeEvent" // 当该元素 被放大缩小触发的事件 @move="moveEvent" // 该元素移动时 触发的事件 @resized="resizedEvent" // 放大缩小结束 触发事件 注意:必须当大小相对上一次发生改变结束时才会触发 @moved="movedEvent" // 移动结束触发 注意:只有当位置相对上一次发生改变才会触发 ></grid-item> // for循环 便利数组中的内容 渲染元素 // <grid-item v-for="item in layout" // :x="item.x" // :y="item.y" // :w="item.w" // :h="item.h" // :i="item.i"> // {{item.i}} //</grid-item> </grid-layout> import VueGridLayout from 'vue-grid-layout' //文件引入 const matedata = [ { i: "0", // 索引值 必填 h: 4, // 高度 必填 w: 7, // 宽度 必填 x: 2, // x 轴距离 必填 y: 0, // y轴距离 必填 minW:5 // 最小宽度 当 w的值小于minW时 采用minW的值 minH:3 // 同上 maxW:8 // 的最大宽度。如果w大于maxW,那么w将被设置为maxW。 maxH:6 // 同上 isDraggable:true // 单独控制这一个盒子是否可以拖动 未填写 继承父元素的 非必填 isResizable:true // 单独控制这一个盒子是否可以调整大小 未填写 继承父元素的 非必填 static:false // 这个盒子是静态的 不能被其他元素改变位置 会被覆盖在底部 dragIgnoreFrom: '' // 属性这值为css 选择器 项的哪些元素不应触发项的拖动事件// 具体不知道干嘛的 没有用到 dragAllowFrom:'' // 属性这值为css 选择器 项的哪些元素应触发项的拖动事件 // 文档这样写的 resizeIgnoreFrom:''//属性这值为css 选择器 表示项的哪些元素不应触发项的调整大小事件。//来自文档翻译 }, { h: 1, i: "1", w: 1, x: 0, y: 1 }, { h: 1, i: "2", w: 1, x: 0, y: 2 }, { h: 1, i: "3", w: 1, x: 0, y: 3 } ]; export default { data() { return { layoutData: matedata, // 存放布局数据 数据格式如上 }; }, components: { GridLayout, //注册组件 GridItem // 注册 }, methods: { // 布局中单元改变事件 i, newX, newY 移动的坐标 // i, newH, newW, newHPx, newWPx 变化的大小 //newHPx, newWPx 是实际的像素 // newH, newW 是数据中的 以每个单位大小为基准点算 resizeEvent(i, newH, newW, newHPx, newWPx) { console.log("大小正在改变",i, newH, newW, newHPx, newWPx); }, moveEvent( i, newX, newY) { console.log("正在移动",i, newX, newY); }, resizedEvent(i, newH, newW, newHPx, newWPx) { console.log("大小改变完了",i, newH, newW, newHPx, newWPx); }, movedEvent( i, newX, newY) { console.log("移动结束了", i, newX, newY); }, // 布局组件的生命周期 参数newLayout=> 布局的数据 每个布局数据 layoutCreatedEvent(newLayout) { console.log("1Created"); }, layoutBeforeMountEvent(newLayout) { console.log("2Mount"); }, layoutMountedEvent(newLayout) { console.log("3Mounted"); }, layoutReadyEvent(newLayout) { console.log("4Ready"); }, layoutUpdatedEvent(newLayout) { console.log("Updated"); } }, created() { }, mounted() { }; };