Vue Grid Layout -️ 适用Vue.js的栅格布局系统(保姆级使用教程)

news2025/2/27 5:05:11

目录

一、 Vue Grid Layout 简介 

二、vue-grid-layout 的安装与使用

 三、 属性

3.1 gridItem 的必须属性

3.2 框架元素的实际宽度高度计算方式

3.3 gridLayout 的属性

四、事件

五、vue-grid-layout 的实际应用

5.1 移动到任意位置

5.2  移动事件与调整大小

5.3 实现两个元素的交换

         5.4 指定允许拖动的元素

5.5 动态添加/删除元素

5.6 外部添加元素

5.7 动态拖拽预览

六、 Vue3 的使用

 总结


兄弟们,有啥好的录屏gif工具推荐一下?

官网:Vue Grid Layout -️ 适用Vue.js的栅格布局系统

Gitee:https://gitee.com/wfeng0/vue2-grid-layout 

一、 Vue Grid Layout 简介 

在官网的描述中,我们可以看出,该栅格布局具有以下特性:

 在具有拖拽组成页面、组件动态调整大小、边缘碰撞监测的系统中,使用该布局无疑是最合适的。当然,目前也有很多现成的文章、博客,今天主要按照官网的学习思路,讲解一下该栅格系统的基本使用。

该栅格系统目前对 vue2 的支持是最好的,vue3 是需要用插件支持的,会在小节详细讲解。

二、vue-grid-layout 的安装与使用

// 安装:
npm install vue-grid-layout --save

// 引用:
import { GridLayout, GridItem } from 'vue-grid-layout'

// 注册:
components:{ GridLayout, GridItem }

完成上诉步骤之后,复制官网的《用法》一节代码到项目中:

data() {
        return {
            // 定义栅格系统数据源
            layout: [
                { "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" }
            ],

        }
    },
 <grid-layout
            :layout.sync="layout"
            :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 layout"
                   :x="item.x"
                   :y="item.y"
                   :w="item.w"
                   :h="item.h"
                   :i="item.i"
                   :key="item.i">
            {{item.i}}
        </grid-item>
    </grid-layout>

得到如下图,即表示该栅格系统已经能正常使用了,下面慢慢介绍其属性与事件方法。

  给 gridItem(是item) 添加样式:

 <grid-item v-for="item in layout" :x="item.x" :y="item.y" 
     :w="item.w" :h="item.h" :i="item.i" :key="item.i" class="gridItem">
            {{ item.i }}
        </grid-item>

// 对应的less
<style lang="less" scoped>
.gridItem {
    border: solid black 1px;
    background-color: #CCCCCC;
}
</style>

这样子,是不是就很像官网的例子了 

 三、 属性

简单说一下经常用到的属性,所有的属性可以前往官网查看描述,我们先来了解一下gridItem的必要属性吧,它对我们的讲解是非常重要的。

3.1 gridItem 的必须属性

这是gridItem的数据项:{ "x": 0, "y": 0, "w": 2, "h": 2, "i": "0" },包含x、y、w、h、i。

    *   1. i:  栅格中元素的ID

    *   2. x: 标识栅格元素位于第几列

    *   3. y: 标识栅格元素位于第几行

    *   4. w: 标识栅格元素的初始宽度(值为colWidth的倍数)

    *   5. h: 标识栅格元素的初始高度(值为rowHeight的倍数)

 理解基本概念后,详细说说参数含义(只取第一个数据项:{ "x": 0, "y": 0, "w": 2, "h": 2, "i": "0" }): 

将X设为5:

 将Y设为3:【目前无法设置为3,因为item会一直处于第一行,稍后再处理,因为现在还不能处于随意位置】

 而W、H就相对简单了,控制数据项的宽度、高度: 

    *   6. minW:栅格元素的最小宽度(值为colWidth的倍数)

    *   7. minH:栅格元素的最小高度(值为rowHeight的倍数)

    *   8. maxW:栅格元素的最大宽度(值为colWidth的倍数)

    *   9. maxH:栅格元素的最大高度(值为rowHeight的倍数)

了解了基本属性后,我们可以看GridLayout的属性了,因为item的其他属性会继承父级属性,在看其元素前,我们需要知道框架的元素计算方法。

3.2 框架元素的实际宽度高度计算方式

图示:vue-grid-layout 的格子数示意

已知colNum是定义列数,rowHeight是指每一行的高度(这个的单位是 px); 如上图,将父盒子拆分为三行、五列,我放一个格子元素,实际占比是下图:

 元素的实际高宽,等于一个格子的尺寸,问:占2×2个格子数的元素尺寸呢?

用代码验证一下:

就是需要理解margin的存在即可。 因此可以得出结论

// 元素的尺寸计算方法
宽度 width = ( box / colNum ) * w + ( w - 1 ) * margin + border
高度 height= rowHeight * h +( h - 1 ) * margin + border

我们用代码验证一下这个格子数:

 

grid-layout 下可以放多个grid-item,我们用一个做背景框,一个做拖拽,背景框不可拖拽、不可缩放:is-draggable="false" :is-resizable="false",注意顺序,放在第一个会在最下面,效果如下。

 这样更清晰看到,缩放后,元素的尺寸确实是包含margin值的。

元素的宽高与实际的w、h值,是存在一个加上(n-1)的margin值的关系, 花了很大篇幅说明了这个框架的宽高计算方式,一定记得是(n-1)的关系,在页面上计算元素尺寸时,别忘了margin的存在!

3.3 gridLayout 的属性

    *  1. layout:栅格布局的数据源,数据源为数组Array,数据项为对象,必须包含 i, x, y, w 和 h 属性.

     *  2. colNum:定义栅格系统的列数

     *  3. rowHeight:每行的高度,单位像素

     *  4. maxRows:定义最大行数

     *  5. isDraggable:标识栅格中的元素是否可拖拽

     *  6. isResizable:标识栅格中的元素是否可调整大小

     *  7. preventCollision:防止碰撞属性,值设置为ture时,栅格只能拖动至空白处

(我们将数据项宽度高度设为1,便于查看效果)

colNum:是定义列数

 rowHeight:是指每一行的高度(这个的单位是 px)

 margin:定义栅格中的元素边距(数组中第一个元素表示水平边距,第二个表示垂直边距,单位为像素)

其他属性就比较简单了,不再大篇幅介绍了,后面遇到了我们再细说。主要大家一定要了解计算规则,这个框架就非常容易掌握了,遇到BUG,基本上是margin的问题。

四、事件

官网描述:事件 | Vue Grid Layout -️ 适用Vue.js的栅格布局系统

这章节官网已经描述得非常好了,也有demo、样例,我就不细说了。

五、vue-grid-layout 的实际应用

5.1 移动到任意位置

上诉还遗留一个问题没处理,就是元素不能移动到任意位置

gridLayout  verticalCompact 属性: 标识布局是否垂直压缩,为false时,垂直方向不压缩,可以放置元素。

 5.2  移动事件与调整大小

事件分两组,事件执行中和事件执行完毕。

移动事件有三个参数:i、newX、newY,i标识唯一移动元素ID和新的位置

         @move="moveEvent"

        @moved="movedEvent"

调整大小事件有5个参数:i、newH、newW及h、w的px(像素)单位

        @resize="resizeEvent"

        @resized="resizedEvent"

常用的事件就是这两组,我们也会详细说明及应用。

5.3 实现两个元素的交换

元素的交换是最简单的应用,当元素覆盖到一个元素上时,交换两者的位置。类似交换两个数,一定需要第三个变量,我们使用深拷贝的方式实现数据缓存。

mounted() {
    this.map = JSON.parse(JSON.stringify(this.layout));
  },

实现思路:移动中,判断位置上是否有元素,有的话,交换两者数据即可。

moveEvent(i, x, y) {
      console.log("移动中--move", i, x, y);
      //   1 根据移动位置,循环数据源当前位置是否有元素,不包含自己的位置
      const finditem = this.map.find(
        (item) => item.x === x && item.y === y && item.i != i
      );
      if (!finditem) return;
      console.log("找到了", finditem);
      this.changePosition(
        this.layout.find((item) => item.i === i),
        finditem
      );
    },

 逻辑理清后,开始交换了:

// 交换位置:
    changePosition(item1, item2) {
      console.log(item1, item2);
      // 定义中间变量交换
      const temp = this.deepClone(item1);
      //   注意:修改的是影响显示的实际数组 layout
      this.layout.forEach((item) => {
        // 找到 item1,将 item1 的信息换成item2
        if (item.i === item1.i) {
          item.x = item2.x;
          item.y = item2.y;
        }
        if (item.i === item2.i) {
          item.x = temp.x;
          item.y = temp.y;
        }
      });
      // 实现交换后,及时同步 数据映射
      this.map = this.deepClone(this.layout);
    },

但是这样还有一个小问题,我希望是两个原始位置交换,而不是移动过程中的最新位置,这就需要获取数据映射中的原始数据:

实现效果: 

简单实现到这就行了,当然还有其他的问题,比如相同尺寸的才能交换、多换少、匹配后非立马交换等问题,还是影响用户体验的,我们将这些问题留后面处理。

5.4 指定允许拖动的元素

这个场景比较常见,在实际项目中,不可能整体结构允许拖动,因为要涉及结构的事件响应等,因此,为其设计允许拖动的元素就比较重要了。

【GridItem 属性】

# dragIgnoreFrom(标识栅格元素中哪些子元素无法触发拖拽事件,值为css-like选择器)

# dragAllowFrom (标识栅格元素中哪些子元素可以触发拖拽事件,值为css-like选择器)

<grid-item
        v-for="item in layout"
        :x="item.x"
        :y="item.y"
        :w="item.w"
        :h="item.h"
        :i="item.i"
        :key="item.i"
        @move="moveEvent"
        @moved="movedEvent"
        @resize="resizeEvent"
        @resized="resizedEvent"
        class="gridItem"
        :style="{ backgroundColor: item.i === '0' ? '' : 'pink' }"
        drag-ignore-from=".gridBox"
        drag-allow-from=".draggable"
      >
        <div class="gridBox">不允许拖动</div>
        <div class="draggable"></div>
      </grid-item>
.gridItem {
    position: relative;
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    border: solid #fff 1px;
    background-color: #cccccc;

    .draggable {
      position: absolute;
      left: 0;
      top: 0;
      width: 10px;
      height: 10px;
      background-color: #000;
      border-radius: 10px;
      cursor: pointer;
    }
  }

只有指定元素才能拖动,其他未指定的均不允许拖动:

 5.5 动态添加/删除元素

动态添加元素就是往数组对象中 push 新的item数据项:

 add() {
      this.layout.push({
        x: 1,
        y: 2, // puts it at the bottom
        w: 1,
        h: 1,
        i: this.layout.length + 1,
      });
    },

 而删除元素,就是获取元素的i,执行 this.layout.splice(index, 1) 操作。

dele(i) {
      this.layout.splice(
        this.layout.findIndex((item) => item.i === i),
        1
      );
    },

5.6 外部添加元素

原理就是利用事件源,将外部元素拖动到布局内,动态计算其位置,动态添加元素。

为了计算方便,我们将布局系统放置 top:0,left:0的位置

这里就需要计算我们的格子数、格子宽高。

5.6.1 拖拽到布局内,会得到实时坐标

 事件源中,有  x: 334 y: 161,两个属性.

5.6.2 动态计算释放后,该在什么位置

我们用draged事件监听,移动中事件触发太多次了(事件源是一样的,均有 x、y属性)。

当前坐标 336 299,我们如何确定位于那个格子中(需要格子尺寸做计算)?

按照我们上的计算方法:

// 元素的尺寸计算方法
宽度 width = ( box / colNum ) * w + ( w - 1 ) * margin + border
高度 height= rowHeight * h +( h - 1 ) * margin + border

格子尺寸:  ( box / colNum )* rowHeight,我就不算了,直接获取:

因此,每一个格子尺寸是 270*102,当前坐标 336 299,计算位置【位置指的是在栅格系统中的x、y】:

需要处理 margin ,我们将其归为格子的尺寸,因此,计算时,格子是180*112

336/280=1.2

299/112=2.6

我们向上取整:应该在第三行、第二列。

 能获取到坐标后动态push元素:

 // 动态添加元素
      this.layout.push({
        x: gx - 1,
        y: gy - 1,
        w: 1,
        h: 1,
        i: `item(x:${ex},y:${ey})`,
      });

 5.7 动态拖拽预览

上面实现太生硬了,我们拖进去,不知道其具体位置,我们做一个预览功能.(新的grid-item)

拖动到某一个格子时,能实时展现预览位置能更好。新建 grid-item,使用 previewData:[]空数组做数据源,拖拽事件执行过程中,动态添加preview的数据,实时更新预览数据,这样的交互是最好的:

六、 Vue3 的使用

vue3 需要插件支持:

npm install vue-grid-layout@3.0.0-beta1 --save

// main.js
import VueGridLayout from 'vue-grid-layout'
createApp(App).use(VueGridLayout).mount('#app')

// 在main.js注册后,不需要在 import 引入,直接使用

 总结

栅格布局难度不大,但是要理解里面的原理,并实际应用到自己的项目开发,还要结合自己项目的实际情况。里面涉及的逻辑主要是计算宽高、拖拽事件处理等多角度问题,想要实现更加丰富的功能,主要是能使用多个 item 系统,实现堆叠效果。优化部分留给大家思考了,有问题欢迎交流讨论。别忘了推荐些gif工具哈~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/405283.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Vue显示图片的几种方式

前言 最近在做自己的项目&#xff0c;有这么一个需求&#xff0c;用户列表需要展示用户的头像&#xff0c;之前一直没有处理&#xff0c;趁着这次机会&#xff0c;正好分享下我的解决过程。 头像这一栏空荡荡的&#xff0c;我这种强迫症患者难受死&#xff01; 首先声明下&am…

vue面试题整理(2022-持续更新中...)

vue中MVVM的理解 M&#xff1a;模型&#xff08;Model&#xff09;&#xff1a;数据模型&#xff1b;负责数据存储。泛指后端进行的各种业务逻辑处理和数据操控&#xff0c;主要围绕数据库系统展开。 V就是&#xff1a;View 视图&#xff1a; 负责页面展示&#xff0c;也就是用…

IDEA使用vue的安装与配置(详细教程)

在idea中使用vue首先idea的配置以及环境要搭建好&#xff0c;然后就按照以下操作进行就可以&#xff01;&#xff08;注&#xff1a;我使用的idea是2021.1.3 版本&#xff09; 第一步 去官网下载node.js ,官网地址&#xff1a;https://nodejs.org/en/ 然后进行安装&#xff0…

封装一个uniapp的全局弹窗组件,vue中也可以使用,在任何页面都可以弹出

效果图&#xff1a; 场景&#xff1a; 当你对接websocket时&#xff0c;或者轮询也好&#xff0c;你需要获取到最新的信息&#xff0c;并且在任何页面弹出一个组件进行后续操作 思路&#xff1a; 1、先封装好要弹出的公共组件 2、向vue原型上挂载全局方法&#xff0c;拿到组件真…

VUE2安装步骤

一、node.js安装和配置 1.安装前&#xff0c;先看看自己电脑上有没有node.js 打开命令提示符&#xff0c;尽量选择管理员身份打开&#xff0c;或者按winR&#xff0c;输入cmd打开也行 打开后输入node -v 查看自己电脑是否安装node&#xff0c;以及版本号 node -v 我这里显示v…

vsCode中vue文件无法提示html标签

铅笔头课堂&#xff0c;有态度的前端培训 今天有同学问到老师&#xff1a;“ 老师&#xff0c;我的vue文件里书写html代码不提示了 ”&#xff0c;这个问题别说还真有点冷门&#xff0c;老师研究了一番之后终于妥善修复了这个问题&#xff0c;这里就将处理结果记录下来&#xf…

如何部署WebSpoon9.0.0(Kettle的Web版本)

前言 Kettle 是小有名气的开源ETL工具&#xff0c;现已改名为PDI&#xff08;Pentaho Data Integration&#xff09;&#xff0c;其Web版本为&#xff1a;WebSpoon&#xff0c;本文记录了从官方Git仓库中拉取代码并成功运行的过程。 一、在本地拉取并编译项目 参考来源&#…

基于Echarts实现可视化数据大屏大数据可视化

前言 &#x1f680; 基于 Echarts 实现可视化数据大屏响应式展示效果的源码,&#xff0c;基于htmlcssjavascriptecharts制作&#xff0c; 可以在此基础上重新开发。 本项目中使用的是echarts图表库&#xff0c;ECharts 提供了常规的折线图、柱状图、散点图、饼图、K线图&…

flex 的 三个参数:flex-grow、flex-shrink、flex-basis

前言&#xff1a; 之前对于 flex 布局没有太深刻的理解&#xff0c;往往就只是给 父元素加上 display&#xff1a;flex 属性&#xff0c;在近期学习的过程中了解到 flex 属性是 flex-grow、flex-shrink、flex-basis 三个属性的缩写&#xff0c;来看下面这一个例题&#xff0c…

基于Java Web的图书管理系统

目录 1.系统简要概述 2.系统主要用到的数据库表 3.主要功能 管理员&#xff1a; 用户&#xff1a; 3.1管理员功能 3.11登录 3.12添加学生 3.13查看学生 3.14删除学生 3.15添加书籍 3.16查看书籍 3.2用户端功能 3.2.1登录 3.2.2注册 3.2.3查询图书 3.2.4借阅书籍…

前端实现分页效果

前言 在实际开发中&#xff0c;大部分分页都是配合后端完成的。但是&#xff0c;有时候并不是这样&#xff0c;并非不是这样。后端会一次性返回所有的数据&#xff0c;而我们前端不可能展示所有数据&#xff0c;而是弄一个分页效果。还有一些场景也是需要前端自己弄的分页&…

JavaWeb项目(登录注册页面)全过程详细总结

JavaWeb项目(登录注册页面)全过程总结 文章目录JavaWeb项目(登录注册页面)全过程总结一、环境准备与开发工具二、创建 JavaWeb 项目2.1 新建Dynamic Web Project项目2.2 创建前端页面2.2.1 登录页面1.login.jsp2. login.js3. time.js4. focus.js animate.js2.2.2 注册页面&…

如何使用nvm切换npm版本

我比较懒惰,如非必要,不喜欢npm版本切换来切换去,感觉浪费我编程的时间.后来发现,现在偷的懒都是为将来的忙碌埋下的祸根. 言归正传,本文主要是讲解一下,如何使用nvm进行npm版本的切换. 工欲善其事必先利其器,我们先下载nvm;直接上下载链接(针对windows哈,毕竟我没mac本); 下载…

前端开发工程师简历

简历是什么 找工作之前投递的个人信息和工作能力----不全面 应该是&#xff1a;个人当前阶段的价值体现 前者&#xff1a;我能卖多少钱&#xff1b;后者&#xff1a;我现在值多少钱 建议&#xff1a;每隔半年/一年给自己做总结的时候写一份简历&#xff08;相当于个人价值总结…

render函数

render函数 通常我们都会把我们的页面结构逻辑都写在 template 中&#xff0c;然后再通过vue将我们的代码转换成虚拟DOM&#xff0c;相比于真实DOM&#xff0c;虚拟DOM是通过js代码处理的&#xff0c;所以消耗的性能相对较小&#xff0c;当然大部分情况下使用 template 创建我…

(详解)Vue设置select下拉框的默认选项(解决select空白的bug)

最近在用vue设置表单数据时发现了一个小问题&#xff1a;用vue动态渲染select下拉框时&#xff0c;select下拉框会出现空白的bug。 <template><div><select name"art-cate" v-model"select"><option disabled selected style"d…

Vue项目启动出现的问题及解决方法

今天在公司入职第二天&#xff0c;昨天拉下来的代码没有跑起来&#xff0c;看了各种博客也没有解决这个报错 今天一大早来公司&#xff0c;捋了一下顺序 ①删除要启动项目里的 node_modules 文件夹&#xff0c;这是vue项目的依赖包。 因为“node_modules”文件夹太大&#x…

《Vue插件》瀑布流插件vue-masonry的使用与踩坑记录

这是一个没有套路的前端博主&#xff0c;热衷各种前端向的骚操作&#xff0c;经常想到哪就写到哪&#xff0c;如果有感兴趣的技术和前端效果可以留言&#xff5e;博主看到后会去代替大家踩坑的&#xff5e; 主页: oliver尹的主页 格言: 跌倒了爬起来就好&#xff5e; 《Vue插件…

Moment.js的基本使用

一、Moment.js的简介 Moment.js是一个轻量级的JavaScript时间库&#xff0c;以前我们转化时间&#xff0c;都会进行很复杂的操作&#xff0c;而Moment.js的出现&#xff0c;简化了我们开发中对时间的处理&#xff0c;提高了开发效率。日常开发中&#xff0c;通常会对时间进行下…

React面试题最全

1.什么是虚拟DOM&#xff1f; 虚拟DOM是真实DOM在内存中的表示&#xff0c;ul的表示形式保存在内存中&#xff0c;并且与实际的DOM同步&#xff0c;这是一个发生在渲染函数被调用和元素在屏幕上显示的步骤&#xff0c;整个过程被称为调和 2.类组件和函数组件之间的区别是什么…