Vue 可拖拽组件 vue-grid-layout 使用入门
介绍
- 官网:https://jbaysolutions.github.io/vue-grid-layout/
- GitHub:https://github.com/jbaysolutions/vue-grid-layout
- npmjs:https://www.npmjs.com/package/vue-grid-layout
特性
- 可拖拽
- 可调整大小
- 静态部件(不可拖拽、调整大小)
- 拖拽和调整大小时进行边界检查
- 增减部件时避免重建栅格
- 可序列化和还原的布局
- 自动化 RTL 支持
- 响应式
安装
npm install vue-grid-layout --save
属性
GridLayout
layout
数据源。值必须为
Array
,其数据项为Object
。 每条数据项必须有i
,x
,y
,w
和h
属性。 请参考下面的GridItem
。responsiveLayouts
如果
responsive
设置为true
,该配置将作为栅格中每个断点的初始布局。键值是断点名称,每项的值都是类似layout
属性定义的数据结构,值必须为Array
,其数据项为Object
。例如:{lg: [layout items], md: [layout items]}
。需要注意的是,在创建栅格布局后设置该属性无效。colNum
定义栅格系统的列数,其值需为自然数。
rowHeight
每行的高度,单位像素。
maxRows
定义最大行数。
margin
定义栅格中的元素边距。
值必须是包含两个
Number
的数组,数组中第一个元素表示水平边距,第二个表示垂直边距,单位为像素。isDraggable
标识栅格中的元素是否可拖拽。
isResizable
标识栅格中的元素是否可调整大小。
isMirrored
标识栅格中的元素是否可镜像反转。
autoSize
标识容器是否自动调整大小。
verticalCompact
标识布局是否垂直压缩。
useCssTransforms
标识是否使用 CSS 属性
transition-property: transform;
。responsive
标识布局是否为响应式。
breakpoints
为响应式布局设置断点。
cols
设置每个断点对应的列数。
useStyleCursor
标识是否使用动态鼠标指针样式。当拖动出现卡顿时,将此值设为
false
也许可以缓解布局问题。
GridItem
i:栅格中元素的 ID。
x:标识栅格元素位于第几列,需为自然数。
y:标识栅格元素位于第几行,需为自然数。
w:标识栅格元素的初始宽度,值为
colWidth
的倍数。h:标识栅格元素的初始高度,值为
rowHeight
的倍数。minW:栅格元素的最小宽度,值为
colWidth
的倍数。如果w
小于minW
,则minW
的值会被w
覆盖。minH:栅格元素的最小高度,值为
rowHeight
的倍数。如果h
小于minH
,则minH
的值会被h
覆盖。maxW:栅格元素的最大宽度,值为
colWidth
的倍数。如果w
大于maxW
,则maxW
的值会被w
覆盖。maxH:栅格元素的最大高度,值为
rowHeight
的倍数。如果h
大于maxH
,则maxH
的值会被h
覆盖。isDraggable:标识栅格元素是否可拖拽。如果值为
null
则取决于父容器。isResizable:标识栅格元素是否可调整大小。如果值为
null
则取决于父容器。static:标识栅格元素是否为静态的(无法拖拽、调整大小或被其他元素移动)。
dragIgnoreFrom:标识栅格元素中哪些子元素无法触发拖拽事件,值为
css-like
选择器。请参考 interact.js docs 中的
ignoreFrom
。dragAllowFrom:标识栅格元素中哪些子元素可以触发拖拽事件,值为
css-like
选择器。如果值为null
则表示所有子元素(dragIgnoreFrom
的除外)。请参考 interact.js docs 中的
allowFrom
。resizeIgnoreFrom:标识栅格元素中哪些子元素无法触发调整大小的事件,值为
css-like
选择器。请参考 interact.js docs 中的
ignoreFrom
。
基础使用
引入
import VueGridLayout from 'vue-grid-layout';
加入到 Vue 组件
export default { components: { GridLayout: VueGridLayout.GridLayout, GridItem: VueGridLayout.GridItem }, data() { return { layoutData: [] }; }, methods: { init() { this.layoutData = [ {"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"}, {"x":8,"y":0,"w":2,"h":3,"i":"4"}, {"x":10,"y":0,"w":2,"h":3,"i":"5"}, {"x":0,"y":5,"w":2,"h":5,"i":"6"}, {"x":2,"y":5,"w":2,"h":5,"i":"7"}, {"x":4,"y":5,"w":2,"h":5,"i":"8"}, {"x":6,"y":3,"w":2,"h":4,"i":"9"}, {"x":8,"y":4,"w":2,"h":4,"i":"10"}, {"x":10,"y":4,"w":2,"h":4,"i":"11"}, {"x":0,"y":10,"w":2,"h":5,"i":"12"}, {"x":2,"y":10,"w":2,"h":5,"i":"13"}, {"x":4,"y":8,"w":2,"h":4,"i":"14"}, {"x":6,"y":8,"w":2,"h":4,"i":"15"}, {"x":8,"y":10,"w":2,"h":5,"i":"16"}, {"x":10,"y":4,"w":2,"h":2,"i":"17"}, {"x":0,"y":9,"w":2,"h":3,"i":"18"}, {"x":2,"y":6,"w":2,"h":2,"i":"19"} ]; } }, created() { this.init() } }
加入网格
<template> <div class="dashboard-container"> <grid-layout :layout="layoutData" :col-num="12" :row-height="30" :is-draggable="true" :is-resizable="true" :is-mirrored="false" :vertical-compact="true" :margin="[10, 10]" :use-css-transforms="true"> <grid-item v-for="item in layoutData" :x="item.x" :y="item.y" :w="item.w" :h="item.h" :i="item.i" :key="item.i"> {{item.i}} </grid-item> </grid-layout> </div> </template>
加上点背景颜色
.vue-grid-item { background: aquamarine; }
预览效果
添加右键事件
在基础使用的基础上,增加如下配置:
增加按钮
<template> <div class="dashboard-container"> <ul class='contextmenu' v-show="menuConfig.visible" :style="{left:menuConfig.left+'px',top:menuConfig.top+'px'}"> <li @click="test(1)">1</li> <li @click="test(2)">2</li> <li @click="test(3)">3</li> </ul> <grid-layout :layout="layoutData" :col-num="6" :row-height="30" :is-draggable="true" :is-resizable="true" :is-mirrored="false" :vertical-compact="true" :margin="[10, 10]" :use-css-transforms="true" > <grid-item v-for="item in layoutData" :x="item.x" :y="item.y" :w="item.w" :h="item.h" :i="item.i" :key="item.i"> <div class="layout-Box" @contextmenu.prevent="openMenu(item, $event)"> {{ item.i }} </div> </grid-item> </grid-layout> </div> </template>
增加 Data 相关配置
data() { return { menuConfig: { visible: false, left: 0, top: 0 } }; }, methods: { // 右键打开菜单 openMenu(tag, e) { this.menuConfig.visible = true this.menuConfig.left = e.clientX this.menuConfig.top = e.clientY }, // 关闭菜单 closeMenu() { this.menuConfig.visible = false }, // 测试方法 test(i) { console.log(i) } }, watch: { 'menuConfig.visible':function(val,oldval){ if (this.menuConfig.visible) { document.body.addEventListener('click', this.closeMenu) } else { document.body.removeEventListener('click', this.closeMenu) } } }
CSS
.layout-Box{ width: 100%; height: 100%; } .contextmenu { margin: 0; background: #fff; z-index: 100; position: absolute; list-style-type: none; padding: 5px 0; border-radius: 4px; font-size: 12px; font-weight: 400; color: #333; box-shadow: 2px 2px 3px 0 rgba(0, 0, 0, .3); li { margin: 0; padding: 7px 16px; cursor: pointer; &:hover { background: #eee; } } }
预览效果: