vue-grid-layout是一个适用于vue的拖拽栅格布局库,功能齐全,适用于拖拽+高度/宽度自由调节的布局需求,本文将讲述一些常用参数和事件,以及做一个同步拖拽的Demo。效果动态图如下:
npm install vue-grid-layout --save
npm install [email protected] --save
属性名 | 类型 | 必填 | 默认值 | 描述 |
---|---|---|---|---|
layout | Array | 是 | - | 数据源,每一项必须有i, x, y, w 和 h属性 |
colNum | Int | 否 | 12 | 列数 |
rowHeight | Int | 否 | 150 | 每行的高度像素 |
maxRows | Int | 否 | Infinity | 最大行数 |
margin | Array | 是 | [10, 10] | 元素边距 |
isDraggable | Boolean | 否 | true | 是否可拖拽 |
isResizable | Boolean | 否 | true | 是否可调整大小 |
isMirrored | Boolean | 否 | false | 是否可镜像反转 |
autoSize | Boolean | 否 | true | 是否自动调整大小 |
verticalCompact | Boolean | 否 | true | 布局是否垂直压缩 |
preventCollision | Boolean | 否 | false | 防止碰撞,为true则元素只能拖动至空白处 |
useCssTransforms | Boolean | 否 | true | 是否使用CSS属性 transition-property: transform |
responsive | Boolean | 否 | false | 布局是否为响应式 |
breakpoints | Boolean | 否 | { lg: 1200, md: 996, sm: 768, xs: 480, xxs: 0 } | 为响应式布局设置断点 |
cols | Boolean | 否 | { lg: 12, md: 10, sm: 6, xs: 4, xxs: 2 } | 设置每个断点对应的列数 |
属性名 | 类型 | 必填 | 默认值 | 描述 |
---|---|---|---|---|
i | string | 是 | - | 子项ID |
x | number | 是 | - | 元素位于第几列 |
y | number | 是 | - | 元素位于第几行 |
w | number | 是 | - | 初始宽度,值必须为colNum的倍数 |
h | number | 是 | - | 初始高度,值必须为rowHeight的倍数 |
minW | number | 否 | 1 | 元素最小宽度,值必须为colNum的倍数,如果w小于minW,则minW的值会被w覆盖 |
minH | number | 否 | 1 | 元素最小高度,值必须为rowHeight的倍数,如果h小于minH,则minH的值会被h覆盖 |
maxW | number | 否 | Infinity | 元素最大宽度,值必须为colNum的倍数,如果w大于maxW,则maxW的值会被w覆盖 |
maxH | number | 否 | Infinity | 元素最大高度,值必须为rowHeight的倍数,如果h大于maxH,则maxH的值会被h覆盖 |
isDraggable | Boolean | 否 | null | 是否可拖拽。如果值为null则取决于父容器 |
isResizable | Boolean | 否 | null | 是否可调整大小。如果值为null则取决于父容器 |
static | Boolean | 否 | false | 是否为静态的,无法拖拽、调整大小或被其他元素移动 |
dragIgnoreFrom | string | 否 | ‘a, button’ | 标识哪些子元素无法触发拖拽事件,值为css-like选择器 |
dragAllowFrom | string | 否 | null | 标识哪些子元素可以触发拖拽事件,值为css-like选择器,如果值为null则表示所有子元素 |
resizeIgnoreFrom | string | 否 | ‘a, button’ | 标识哪些子元素无法触发调整大小的事件,值为css-like选择器 |
事件名 | 描述 |
---|---|
layoutCreatedEvent | 对应Vue生命周期的created |
layoutBeforeMountEvent | 对应Vue生命周期的beforeMount |
layoutMountedEvent | 对应Vue生命周期的mounted |
layoutReadyEvent | 当完成mount中的所有操作时生成的事件 |
layoutUpdatedEvent | 布局更新或栅格元素的位置重新计算事件 |
breakpointChangedEvent | 断点更改事件,每次断点值由于窗口调整大小而改变 |
事件名 | 描述 |
---|---|
moveEvent | 移动时的事件 |
resizeEvent | 调整大小时的事件 |
movedEvent | 移动后的事件 |
resizedEvent | 调整大小后的事件 |
containerResizedEvent | 栅格元素/栅格容器更改大小的事件(浏览器窗口或其他) |
直接覆盖默认的class样式
.vue-grid-item.vue-grid-placeholder {
background: red;
opacity: 0.2;
transition-duration: 100ms;
z-index: 2;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
-o-user-select: none;
user-select: none;
}
.vue-grid-item.vue-grid-placeholder {
background: green !important;
}
注:本案例是按照vue3的写法
<div class="grid_box">
<div class="left">
<grid-layout
v-model:layout="layoutLeft"
:col-num="4"
:row-height="50"
:is-draggable="true"
:is-resizable="true"
:is-mirrored="false"
:vertical-compact="true"
:margin="[10, 10]"
:use-css-transforms="true"
ref="gridLeftRef"
>
<grid-item
v-for="item in layoutLeft"
:x="item.x"
:y="item.y"
:w="item.w"
:h="item.h"
:i="item.i"
:key="item.i"
@resized="handleGridSync"
@moved="handleGridSync"
>
<div class="left_layout_item">
<div class="del_btn" @click="deleteGrid(item.i)">删div>
<span>{{ item.i }}span>
div>
grid-item>
grid-layout>
div>
<div class="right">
<grid-layout
v-model:layout="layoutRight"
:col-num="4"
:row-height="10"
:is-draggable="true"
:is-resizable="true"
:is-mirrored="false"
:vertical-compact="true"
:margin="[10, 10]"
:use-css-transforms="true"
ref="gridRightRef"
>
<grid-item v-for="item in layoutRight" :x="item.x" :y="item.y" :w="item.w" :h="item.h" :i="item.i" :key="item.i">
<div class="right_layout_item">{{ item.i }}div>
grid-item>
grid-layout>
div>
div>
import VueGridLayout from 'vue-grid-layout'
const gridLeftRef = ref<any>()
const gridRightRef = ref<any>()
const layoutLeft = ref([
{ i: '1', x: 0, y: 0, w: 2, h: 2 },
{ i: '2', x: 2, y: 0, w: 2, h: 2 },
{ i: '3', x: 0, y: 0, w: 2, h: 2 },
{ i: '4', x: 2, y: 0, w: 2, h: 2 }
])
const layoutRight = ref([
{ i: '1', x: 0, y: 0, w: 2, h: 2 },
{ i: '2', x: 2, y: 0, w: 2, h: 2 },
{ i: '3', x: 0, y: 0, w: 2, h: 2 },
{ i: '4', x: 2, y: 0, w: 2, h: 2 }
])
// 处理Grid同步
const handleGridSync = () => {
layoutLeft.value.forEach((item1) => {
layoutRight.value.forEach((item2) => {
if (item1.i === item2.i) {
item2.x = item1.x
item2.y = item1.y
item2.w = item1.w
item2.h = 2
}
})
})
gridLeftRef.value.layoutUpdate()
gridLeftRef.value.updateHeight()
gridRightRef.value.layoutUpdate()
gridRightRef.value.updateHeight()
}
// 创造Grid
const createGrid = () => {
let maxH = 0
layoutLeft.value.forEach((item) => {
if (item.y > maxH) maxH = item.y
})
const uid = createUuid()
layoutLeft.value.push({ i: uid, x: 0, y: maxH, w: 2, h: 2 })
layoutRight.value.push({ i: uid, x: 0, y: maxH, w: 2, h: 2 })
handleGridSync()
}
// 删除Grid
const deleteGrid = (id: string) => {
const idx1 = layoutLeft.value.findIndex((item1) => item1.i === id)
layoutLeft.value.splice(idx1, 1)
const idx2 = layoutRight.value.findIndex((item2) => item2.i === id)
layoutRight.value.splice(idx2, 1)
handleGridSync()
}
本次分享就到这儿啦,我是鹏多多,如果您看了觉得有帮助,欢迎评论,关注,点赞,转发,我们下次见~
往期文章
个人主页