div元素
bash
<grid-layout
:layout="map"
:col-num="10"
:maxRows="6"
:row-height="rowHeight"
:is-draggable="true"
:is-resizable="true"
:autoSize="false"
:is-mirrored="false"
:vertical-compact="true"
:preventCollision = "false"
:margin="[10, 10]"
:use-css-transforms="true"
>
<grid-item v-for="item in map"
:x="item.x"
:y="item.y"
:w="item.w"
:h="item.h"
:i="item.i"
:key="item.i"
@move="moveEvent"
@moved="movedEvent"
@resized="resizeEvent"
class="gridItem">
<h1 >{{item.i}}</h1>
</grid-item>
</grid-layout>
demo数据:
bash
windowHeight: 0,
rowHeight:130,
layout: [
{ x: 0, y: 0, w: 3, h: 2, i: "0"},
{ x: 3, y: 0, w: 4, h: 3, i: "1" },
{ x: 7, y: 0, w: 3, h: 2, i: "2" },
{ x: 0, y: 2, w: 3, h: 2, i: "10" },
{ x: 3, y: 3, w: 4, h: 3, i: "11" },
{ x: 7, y: 2, w: 3, h: 2, i: "12" },
{ x: 0, y: 4, w: 3, h: 2, i: "20" },
{ x: 7, y: 4, w: 3, h: 2, i: "22" },
],
map:[],
curBox:'',
交换的主要方法:
bash
moveEvent(i, x, y) {
this.curBox = i
},
movedEvent(i, x, y){
// 1 根据移动位置,循环数据源当前位置是否有元素,不包含自己的位置
if (y>11) this.map = JSON.parse(JSON.stringify(this.layout));
const item1 = this.layout.find(
(item) => item.x <= x && x < (item.x+item.w) && item.y <=y && (y < item.y+item.h) && item.i != i
);
const item2 = this.layout.find(
(item) => item.i == i
);
// console.log(item1,item2)
item1 && this.changePosition(item1,item2)
if(!item1) this.layout = JSON.parse(JSON.stringify(this.map));
localStorage.setItem("layout",JSON.stringify(this.layout))
},
changePosition(item1, item2) {
// console.log(item1, item2);
// 定义中间变量交换
const temp = JSON.parse(JSON.stringify(item1));
const temp2 = JSON.parse(JSON.stringify(item2));
// 注意:修改的是影响显示的实际数组 map
this.layout.forEach((item) => {
// 找到 item1,将 item1 的信息换成item2
if (item.i === item1.i) {
item.x = temp2.x;
item.y = temp2.y;
item.w = temp2.w
item.h = temp2.h
}
if (item.i === item2.i) {
item.x = temp.x;
item.y = temp.y;
item.w = temp.w;
item.h = temp.h;
}
});
// 实现交换后,及时同步 数据映射
this.map = JSON.parse(JSON.stringify(this.layout));
},
扩展:动态行高、echarts图表动态渲染、指定元素可拖动
动态计算行高:
bash
mounted() {
if (localStorage.getItem('layout')){
this.layout = JSON.parse(localStorage.getItem('layout'))
}
this.map = JSON.parse(JSON.stringify(this.layout));
localStorage.setItem("layout",JSON.stringify(this.layout))
this.onWindowResize()
window.addEventListener('resize', this.onWindowResize); // 添加事件监听器
},
beforeDestroy() {
window.removeEventListener('resize', this.onWindowResize); // 移除事件监听器以避免内存泄漏
},
onWindowResize() {
this.windowHeight = window.innerHeight; // 更新窗口高度
this.rowHeight = (this.windowHeight-(10*7))/6 //margin的高度*(行数+1)
},
echarts图表动态渲染:
bash
//div中,注意data如果是方法中有更新需重新赋值给datalist
<component :is="item.chart" :chart-date="dataList[item.i]"></component>
//实际echarts中动态更新视图内容
const elementResizeDetectorMaker = require("element-resize-detector");
let erd = elementResizeDetectorMaker();
//mounted中(ref对应div绑定的ref)
this.$nextTick(() => {
erd.listenTo(this.$refs.radarBasic, () => {
this.$nextTick(function () {
//使echarts尺寸重置
this.myChart.resize();
});
});
})
指定元素可拖动:drag-ignore-from=".draggable" drag-allow-from=".itemTitle"
bash
<grid-item v-for="item in map"
:x="item.x"
:y="item.y"
:w="item.w"
:h="item.h"
:i="item.i"
:key="item.i"
@move="moveEvent"
@moved="movedEvent"
@resized="resizeEvent"
drag-ignore-from=".draggable"
drag-allow-from=".itemTitle"
class="cardItem_dark cardItem"
> <div class="title-top"></div>
<div class="itemTitle centerItem">{{item.title}}</div>
<div class="draggable" v-if="['2','4','5','7'].includes(item.i)" :style="'width:'+ 9.3*item.w+'vw;'+'height:'+ (rowHeight*item.h+20*(item.h-1.1))+'px;padding-top:5%'">
<component :is="item.chart" :chart-date="dataList[item.i]"></component>
</div>
<div class="draggable" v-else :style="'width:'+ 9*item.w+'vw;'+'height:'+ (rowHeight*item.h+20*(item.h-1.1))+'px;padding-top:5px'">
<component :is="item.chart" :chart-date="dataList[item.i]"></component>
</div>
</grid-item>
参考链接:
Vue Grid Layout - 适用Vue.js的栅格布局系统(项目实例)
Vue Grid Layout -️ 适用Vue.js的栅格布局系统(保姆级使用教程)
Vue Grid Layout 官方文档