1、前言
vue-grid-layout是一個適用于vue的拖拽柵格布局庫,功能齊全,適用于拖拽+高度/寬度自由調(diào)節(jié)的布局需求。本文將講述一些常用參數(shù)和事件,以及做一個同步拖拽的Demo。效果動態(tài)圖如下:

grid-layout.gif
2、安裝
- vue2版本:
npm install vue-grid-layout --save
- vue3版本:
npm install vue-grid-layout@3.0.0-beta1 --save
3、屬性
- GridLayout 容器:
| 屬性名 | 類型 | 必填 | 默認值 | 描述 |
|---|---|---|---|---|
| layout | Array<Object> | 是 | - | 數(shù)據(jù)源,每一項必須有i, x, y, w 和 h屬性 |
| colNum | Int | 否 | 12 | 列數(shù) |
| rowHeight | Int | 否 | 150 | 每行的高度像素 |
| maxRows | Int | 否 | Infinity | 最大行數(shù) |
| margin | Array<number> | 是 | [10, 10] | 元素邊距 |
| isDraggable | Boolean | 否 | true | 是否可拖拽 |
| isResizable | Boolean | 否 | true | 是否可調(diào)整大小 |
| isMirrored | Boolean | 否 | false | 是否可鏡像反轉(zhuǎn) |
| autoSize | Boolean | 否 | true | 是否自動調(diào)整大小 |
| verticalCompact | Boolean | 否 | true | 布局是否垂直壓縮 |
| preventCollision | Boolean | 否 | false | 防止碰撞,為true則元素只能拖動至空白處 |
| useCssTransforms | Boolean | 否 | true | 是否使用CSS屬性 transition-property: transform |
| responsive | Boolean | 否 | false | 布局是否為響應(yīng)式 |
| breakpoints | Boolean | 否 | { lg: 1200, md: 996, sm: 768, xs: 480, xxs: 0 } | 為響應(yīng)式布局設(shè)置斷點 |
| cols | Boolean | 否 | { lg: 12, md: 10, sm: 6, xs: 4, xxs: 2 } | 設(shè)置每個斷點對應(yīng)的列數(shù) |
- GridItem 子項:
| 屬性名 | 類型 | 必填 | 默認值 | 描述 |
|---|---|---|---|---|
| i | string | 是 | - | 子項ID |
| x | number | 是 | - | 元素位于第幾列 |
| y | number | 是 | - | 元素位于第幾行 |
| w | number | 是 | - | 初始寬度,值必須為colNum的倍數(shù) |
| h | number | 是 | - | 初始高度,值必須為rowHeight的倍數(shù) |
| minW | number | 否 | 1 | 元素最小寬度,值必須為colNum的倍數(shù),如果w小于minW,則minW的值會被w覆蓋 |
| minH | number | 否 | 1 | 元素最小高度,值必須為rowHeight的倍數(shù),如果h小于minH,則minH的值會被h覆蓋 |
| maxW | number | 否 | Infinity | 元素最大寬度,值必須為colNum的倍數(shù),如果w大于maxW,則maxW的值會被w覆蓋 |
| maxH | number | 否 | Infinity | 元素最大高度,值必須為rowHeight的倍數(shù),如果h大于maxH,則maxH的值會被h覆蓋 |
| isDraggable | Boolean | 否 | null | 是否可拖拽。如果值為null則取決于父容器 |
| isResizable | Boolean | 否 | null | 是否可調(diào)整大小。如果值為null則取決于父容器 |
| static | Boolean | 否 | false | 是否為靜態(tài)的,無法拖拽、調(diào)整大小或被其他元素移動 |
| dragIgnoreFrom | string | 否 | 'a, button' | 標識哪些子元素無法觸發(fā)拖拽事件,值為css-like選擇器 |
| dragAllowFrom | string | 否 | null | 標識哪些子元素可以觸發(fā)拖拽事件,值為css-like選擇器,如果值為null則表示所有子元素 |
| resizeIgnoreFrom | string | 否 | 'a, button' | 標識哪些子元素無法觸發(fā)調(diào)整大小的事件,值為css-like選擇器 |
4、事件
- GridLayout 容器:
| 事件名 | 描述 |
|---|---|
| layoutCreatedEvent | 對應(yīng)Vue生命周期的created |
| layoutBeforeMountEvent | 對應(yīng)Vue生命周期的beforeMount |
| layoutMountedEvent | 對應(yīng)Vue生命周期的mounted |
| layoutReadyEvent | 當完成mount中的所有操作時生成的事件 |
| layoutUpdatedEvent | 布局更新或柵格元素的位置重新計算事件 |
| breakpointChangedEvent | 斷點更改事件,每次斷點值由于窗口調(diào)整大小而改變 |
- GridItem 子項:
| 事件名 | 描述 |
|---|---|
| moveEvent | 移動時的事件 |
| resizeEvent | 調(diào)整大小時的事件 |
| movedEvent | 移動后的事件 |
| resizedEvent | 調(diào)整大小后的事件 |
| containerResizedEvent | 柵格元素/柵格容器更改大小的事件(瀏覽器窗口或其他) |
5、占位符樣式修改
直接覆蓋默認的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;
}
6、案例
注:本案例是按照vue3的寫法
- HTML:
<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'
- 數(shù)據(jù)源:
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()
}
// 創(chuàng)造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()
}
本次分享就到這兒啦,我是@鵬多多,如果您看了覺得有幫助,歡迎評論,關(guān)注,點贊,轉(zhuǎn)發(fā),我們下次見~
PS:在本頁按F12,在console中輸入document.querySelectorAll('._2VdqdF')[0].click(),有驚喜哦
往期文章
- 超詳細的Cookie增刪改查
- 助你上手Vue3全家桶之Vue3教程
- 助你上手Vue3全家桶之VueX4教程
- 助你上手Vue3全家桶之Vue3教程
- 超詳細!Vuex手把手教程
- 使用nvm管理node.js版本以及更換npm淘寶鏡像源
- 超詳細!Vue-Router手把手教程
- vue中利用.env文件存儲全局環(huán)境變量,以及配置vue啟動和打包命令
- 微信小程序?qū)崿F(xiàn)搜索關(guān)鍵詞高亮
個人主頁