一、回顾上期
通过上一期了解gridstack.js的了解,我们已经知道了怎么去下载插件,并运用gridstack插件实现可拖动、可调整大小、响应式引导友好的布局;知道了一些画布的设置和事件的监听,知道了在this.grid.addWidget( {w: 2, h: 2, content: '添加'})中设置文字、图片等;
二、结合原理
但是当你想要往grid-stack-item里面放入你自己写好的组件;或者嵌入报告、表格、折线图等复杂的组件时,你会想到怎么做?
这里提供的方法就是:1.拿到组件;2.设置组件的参数;3.把组件放进去;
1.结合步骤
1.拿到组件---注册局部组件,引入组件,使用let GirdComponent = Vue.component('A', A)
2.设置组件的参数---使用new创造一个实例对象,我们就可以new GirdComponent({})在其中设置组件的参数;
3.把组件放进去---通过原生js的appendChild(),把组件放入你想放入的grid-stack-item中;
三、实现过程
<template>
<div id="home">
<!-- 左边的添加与删除 -->
<div class="left-box">
<div class="delete-grid">放在这里删除小部件!</div>
<div class="add-grid" draggable="true">把我拖进仪表盘!</div>
</div>
<!-- 右边的grid容器 -->
<div class="right-box">
<div class="grid-stack"></div>
</div>
</div>
</template>
<script>
// 引入gridstack
import "gridstack/dist/gridstack.min.css";
import { GridStack } from "gridstack";
import Vue from "vue";
import barChart from "../EchartsView/EchartsView.vue";
export default {
name: "APP",
data() {
return {
grid: null,
option: {
xAxis: {
type: "category",
data: ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
itemStyle: { color: "red" },
},
yAxis: {
type: "value",
},
series: [
{
data: [120, 200, 150, 80, 70, 110, 130],
type: "bar",
showBackground: true,
backgroundStyle: {
color: "#BBFFFF",
},
itemStyle: {
color: "#EEE9E9",
borderWidth: 1,
borderColor: "#000000",
},
},
],
aria: {
enable: true,
decal: {
show: true,
decals: {
symbol: "rect",
dashArrayX: [2, 0],
dashArrayY: [2, 2],
rotation: 0.523,
color: "#ffffff",
border: 1,
},
},
},
},
};
},
created() {},
mounted() {
this.GridStackInit();
let container = document.querySelector(".right-box");
container.ondragover = function (e) {
e.preventDefault();
};
container.addEventListener("drop", (e) => {
this.addGrid();
});
let deleteGrid = document.querySelector(".delete-grid");
deleteGrid.ondragover = function (e) {
e.preventDefault();
};
deleteGrid.addEventListener("drop", (e) => {});
},
methods: {
GridStackInit() {
let Options = {
dragOut: true,
margin: 5, //网格里面之间的距离
acceptWidgets: true, //接受从其他网格或外部拖动的小部件
dragIn: ".add-grid",
};
// let item7 = document.getElementsByClassName('grid-stack-item7')
this.grid = GridStack.init(Options);
let gridData = [
{ w: 4, h: 2, content: "1" },
{
w: 4,
h: 4,
content: "不能缩放,也不能移动!",
noResize: true,
noMove: true,
},
{ w: 2, h: 2, content: "不能缩放!", noResize: true },
{ w: 2, h: 2, content: "4" },
{ w: 2, h: 2, content: "5" },
{ w: 2, h: 4, content: "6" },
{ w: 4, h: 2, content: "7" },
{ w: 2, h: 2, content: "8" },
{ w: 6, h: 4, id: "card_9" },
{ w: 2, h: 2, content: "10" },
{ w: 2, h: 2, content: "11" },
];
this.grid.load(gridData);
if (this.grid.engine) {
this.grid.engine.nodes.forEach((widget) => {
this.loadGridItem(widget);
});
}
},
addGrid() {
this.grid.addWidget({ w: 2, h: 2, content: "添加" });
},
loadGridItem(widget) {
// 把组件仿佛第九个方块中
if (widget.id == "card_9") {
// 找到第九个方块
let widgetEl = widget.el;
let content = widgetEl.querySelector(".grid-stack-item-content");
let itemDom = document.createElement("div");
itemDom.setAttribute("id", "card_" + widget._id);
// 把组件放入方块中
content.appendChild(itemDom);
// 局部注册组件,组件放入方块中
let WidgetComponent = Vue.component("barChart", barChart);
let instance = new WidgetComponent({
el: "#card_" + widget._id,
propsData: { name: "xiaoming" },
parent: this,
});
// 调整大小,echarts图resize
this.grid.on('resizestop', function(event, gridEl) {
// 当你缩放暂停,触发条件,重新绘图resize
instance.handleResize()
})
}
},
},
};
</script>
<style lang="scss" scoped>
#home {
display: flex;
width: 100vw;
background-color: #44a1ee;
margin: 20px;
}
.left-box {
display: inline;
display: flex;
flex-direction: column;
width: 20%;
border-right: 2px dashed #ffffff;
.delete-grid {
width: 80%;
height: 120px;
background-color: #ee6d44;
border: 2px solid #ffffff;
margin: 20px 0 20px 20px;
}
.add-grid {
width: 80%;
height: 120px;
background-color: #54ff9f;
border: 2px solid #ffffff;
margin: 0 0 0 20px;
}
}
.right-box {
width: 70%;
border: 2px solid #ffffff;
margin: 20px 0 20px 20px;
}
</style>
<style lang="scss">
.grid-stack-item-content {
background-color: #ffffff;
text-align: center;
}
</style>
最后的效果就是这样:我已经把组件放入到了grid-stack-item-content,你需要放入什么组件;局部注册组件,然后根据条件放入其中即可;
四、小结
1.当你想放入不同的组件时
这个遍历出来的widget就是上面的gridData,可以在对象里面加入不同组件的标识type;或者加入接口的参数,当在下面loadGridItem中执行的时候,拿到数据,画出图形;
2.resize重绘
关键事件:grid.on('resizestop',function(event: Event,el: GridItemHTMLElement){});------调整大小结束
(1)当里面是echarts时,触发事件;重绘
(1)当里面是其他组件时,响应式布局;
3.滚动加载
原理就是:滚动的时候触发grid-item,计算每个grid-item的距离(距离上边框、宽度、高度、页面的高度等);
条件:
1.grid-item的高度 > 页面高度;gird-item的顶部或者底部在可是范围内
1.grid-item的高度 < 页面高度;gird-item的顶部和者底部在可是范围内
//监听容器的滚动:得到容器的滚动高度
let gardStackContent = this.$refs.gridStack
gardStackContent.addEventListener('scroll', this.scrollLoad())
//遍历this.grid.engine.nodes:得到grid-item的距离顶部距离和自身高度
let girdItemTop = widget.el.offsetTop
let girdItemBottom = widget.el.offsetTop + widget.el.offsetHeight
let scrollH = scrollTop
4.拖入位置
这里有一个问题,暂时还没有最好的解决办法---替代办法;
1.现在从外面托人一个进来,触发事件,往里面添加一个grid-item
2.但是使用addWidget()始终会放在最后面,因为你没有给这个grid-item,x与y
3.那么在添加的过程中就要计算x 与 y 的位置 和 你鼠标落点位置的关系;
可以看第一期里面从外面拖进来的时候,下面是有一个阴影,然后拖到哪里阴影跟随;上面这个方法暂时做不到这个效果,上一期使用的是clone
缺点就是这里仍然要设置w和h,clone下面的阴影也是根据这个来的;你拖动的是单个的可以实现,如果你拖动的是一个菜单或者多个,展示还没有想到好的办法;有办法解决可留言!!!
五、推荐
这个使用girdStack.ja的人比较少,在网上找到Vue Grid Layout -️ 适用Vue.js的栅格布局系统,两个用法相差不大;但是这个用的人比较多,官网教学详细,建议使用这个。
官网:Vue Grid Layout -️ 适用Vue.js的栅格布局系统