当前位置: 首页 > news >正文

讲讲项目里的仪表盘编辑器(三)布局组件

布局容器处理

        看完前面两章的讲解,我们对仪表盘系统有了一个大概的理解。接着我们讲讲更深入的应用。

        上文讲解的编辑器只是局限于平铺的组件集。而在编辑器中,还会有一种组件是布局容器。它允许其他组件拖拽进入在里面形成自己的一套布局。典型的有分页卡、布局容器等组件。

布局组件的放置

        与前两章提到的普通组件一致。

放置后添加普通组件到布局组件内

        添加普通组件到布局组件内有两种方式:

        第一种:点击添加(选用先选中布局组件)

        怎么实现选中布局组件可以看前面的文章。选中后仓库state的selectedField为当前高亮的布局组件。

        点击添加普通组件,根据仓库里的selectedField判断是否当前选中了布局组件,如果选中,则往选中的布局组件里添加普通组件,如果没有选中的组件或者选中的组件不是布局组件,则按前面章节的点击添加组件生成默认布局属性进入到整体布局之中。

async handleClickAddField(type) {// 布局组件类型const limitType = [// 布局容器DashboardControlTypeEnum.Container,// 分页卡DashboardControlTypeEnum.Tabs,];// 创建普通组件let field = createDashboardField(type);// 当前选择了组件,且选择的组件是布局组件if (this.selectedField && limitType.includes(this.selectedField.type)) {// 新增的普通组件添加父组件属性field.parentId = this.selectedField.pkId;}...}

        上面的代码。只是判断了添加方式为往现有布局组件里添加了普通组件。

        我们先看看如果是嵌套布局(布局容器里有普通组件),此时的this.layout是什么样的?

        现在这个设计器里只有一个布局容器,布局容器里有一个普通组件

        此时this.layout只有一个元素。也就是说grid-layout不承认重叠关系。那么这个画中画是怎么实现的呢?

         也就是布局组件自己内部是个grid-layout,拖拽进去的普通组件被存储到布局组件自身属性上。设计器的grid-layout不关心布局组件内部有多少普通组件,也不关心布局组件内部普通组件怎么排列。

// 最外层布局的组件排列
var layoutFieleds = [// 布局组件{layout:{x:0,y:0,w:30,h:30},// 自身属性widget: {// 布局组件内的组件排列layoutFields: [layout:{x:0,y:0,w:10,h:10},....]}}
]

         那么布局组件的内部怎么实现,我们放到后面讲

         第二种:拖拽添加

        拖拽模型是这样:

// index.vue
<div><a-card><control-list :dragType.sync="dragType" @add="handleClickAddField" /></a-card><a-card :class="$style.main"><drag-container:dragType.sync="dragType"/></a-card>
</div>dragType = null;
// control-list.vue...<div :class="$style.list"><divv-for="control in group.list":key="control.type":draggable="true"@dragstart="handleDragStart(control.type)"@dragend="handleDragEnd"@click.stop="handleAdd(control)"><x-icon :type="control.icon" /><span>{{ control.label }}</span></div>
</div>handleDragStart(type) {this.$emit('update:dragType', type);}handleDragEnd() {this.$emit('update:dragType', null);}

        左边的组件栏拖拽事件只要关注抛出的dragType就行了(要么是空要么是拖拽过去的组件类型)

        index.vue负责把dragType传入到<drag-container>组件里。其他不理会。

// drag-container.vue
<grid-layout@dragover.native="handleDrag"@dragleave.native="handleDragLeave"@drop.native="handleDrop"><grid-itemv-for="layoutItem in layout":key="layoutItem.i"v-bind="getLayoutProps(layoutItem)"><component:is="getComponent(layoutItem)"v-bind="getComponentProps(layoutItem)"@inChildComponent="inChildComponent"/></grid-item>
</grid-layout>

        可以看到,拖拽到布局容器里也是在grid-layout层里处理,而不是gird-item层中特殊处理。

        要看gird-layout上三个drag事件之前,我们需要先搞懂一个叫isInChildCom属性的判断逻辑

// drag-container.vue
@Watch('dragType')
handleDragTypeChange(type) {this.isInChildCom = false; // 重新拖动需要重置...
}

        每次左侧组件栏成功触发/结束拖拽事件,drag-container里的isInChildCom属性就会初始化为false.

        普通组件:

        虽然vue-gird-layout里的item是不支持重叠的。 但是我们依然需要当拖拽组件进入普通组件里面,去emit inChildComponent事件,使drag-cpntainer里的isInChildCom为true。从而阻断后面的放置操作。

// 普通组件<div@dragenter="dragenter"@dragover="dragover"@dragleave="dragleave"@drop="drop">...</div>/** @name 进入-有效目标 **/dragenter() {this.$emit('inChildComponent', true);}dragleave(e) {this.$emit('inChildComponent', false);}

         布局组件:

         布局组件也一样。通过改变isInChildCom 的值为ture,让index.vue拦截拖拽事务。把添加组件的逻辑遗留在布局组件内部进行处理。

// 布局组件<div@dragenter="dragenter"@dragover="dragover"@dragleave="dragleave"@drop="drop">...</div>/** @name 进入-有效目标 **/dragenter() {// 当拖拽的组件是布局组件或无效组件时if (this.limited) this.$emit('inChildComponent', true);this.$emit('inChildComponent', true);}/** @name 离开-有效目标 **/dragleave(e) {if (this.limit) return;const rect = this.$el.getBoundingClientRect();const inside = rectContainPoint(rect, {x: e.clientX,y: e.clientY,});// 确认拖拽组件已经离开布局if (!inside) {this.$emit('inChildComponent', false);// 更新内部布局this.updateInside(e);}}drop(e) {if (this.limit) return...// 添加组件到布局组件内部属性}

             具体的实现请看最后一篇推文

放置后禁止拖拽布局组件到布局组件内

        上一节已经说到了,在布局组件内部的drop系列事件里通过limit去限制(limit的逻辑就是判断拖拽进来的是不是布局组件)。如果是的话,把isInChildCom改成true拦截index层处理,同时布局组件内部也通过limit拦截处理。

删除布局组件内的普通组件

        由布局组件内部控制。详情请最后一篇推文

相关文章:

讲讲项目里的仪表盘编辑器(三)布局组件

布局容器处理 看完前面两章的讲解&#xff0c;我们对仪表盘系统有了一个大概的理解。接着我们讲讲更深入的应用。 上文讲解的编辑器只是局限于平铺的组件集。而在编辑器中&#xff0c;还会有一种组件是布局容器。它允许其他组件拖拽进入在里面形成自己的一套布局。典型的有分页…...

Linux- 后台运行符、nohup、disown

& &在Unix-like的操作系统&#xff08;如Linux和macOS&#xff09;的shell中&#xff0c;特别是在Bash这样的shell中&#xff0c;经常用作后台运行符号。让我们深入了解一下其功能和用法。 &作为后台运行符号&#xff1a; 基本用法: 当我们在一个命令或者一组命令…...

开发过程教学——交友小程序

交友小程序 1. 我的基本信息2. 我的人脉2.1 我的关注2.2 我的粉丝 3. 我的视频4. 我的相册 特别注意&#xff1a;由于小程序分包限制2M以内&#xff0c;所以要注意图片和视频的处理。 1. 我的基本信息 数据库表&#xff1a; 我的基本信息我的登录退出记录我的登录状态&#x…...

正则表达式 Regular Expression学习

该文章内容为以下视频的学习笔记&#xff1a; 10分钟快速掌握正则表达式_哔哩哔哩_bilibili正则表达式在线测试工具&#xff1a;https://regex101.com/, 视频播放量 441829、弹幕量 1076、点赞数 19330、投硬币枚数 13662、收藏人数 26242、转发人数 2768, 视频作者 奇乐编程学…...

代谢组学最常用到的数据分析方法(五)

代谢组学是一门对某一生物或细胞所有低分子质量代谢产物&#xff08;以相对分子质量<1000的有机和无机的代谢物为研究核心区&#xff09;进行分析的新兴学科。因此从复杂的代谢组学数据中确定与所研究的现象有关的代谢物&#xff0c;筛选出候选生物标记物成为代谢物组学研究…...

105.从前序与中序遍历序列构造二叉树

力扣题目链接(opens new window) 根据一棵树的前序遍历与中序遍历构造二叉树。 注意: 你可以假设树中没有重复的元素。 例如&#xff0c;给出 前序遍历 preorder [3,9,20,15,7] 中序遍历 inorder [9,3,15,20,7] 返回如下的二叉树&#xff1a; class Solution { public:Tr…...

分支定界、分支切割、分支定价的区别

目录 1.从原理的角度 &#xff08;1&#xff09;分支定界&#xff1a; &#xff08;2&#xff09;分支切割&#xff1a; &#xff08;3&#xff09;分支定价&#xff1a; 2.从分支树的角度 &#xff08;1&#xff09;分支定界 &#xff08;2&#xff09;分支切割 &…...

数字IC前端学习笔记:数字乘法器的优化设计(阵列乘法器)

相关阅读 数字IC前端https://blog.csdn.net/weixin_45791458/category_12173698.html?spm1001.2014.3001.5482 数字信号处理作为微处理器的核心部件&#xff0c;是决定着总体处理器性能的因素之一&#xff0c;而数字乘法器是最常见的一种数字信号处理电路。通常情况下&#…...

批量删除wordpress文章修订版本/自动草稿残留数据(3种方法)及四种方法禁用WordPress文章历史修订/自动保存/自动草稿功能

目录 1、批量删除wordpress文章修订版本/自动草稿残留数据&#xff08;3种方法&#xff09; 方法一&#xff1a;SQL命令批量删除 命令&#xff1a; 方法二&#xff1a;利用PHP代码来删除 方法三&#xff1a;利用数据库清理优化插件 WP Clean Up 或 WP Cleaner 批量删除 2…...

HTTP初识,fiddler的使用,URL各部分介绍,QueryString

目录 一、什么是HTTP 二、抓包工具 三、请求的首行 URL 四、URL的各部分详细介绍 一、什么是HTTP 现在网页上&#xff0c;我们常见的是https,但是在二十年前是以http为主&#xff0c;这个协议也叫超文本传输协议&#xff0c;文本->字符串&#xff0c;“超文本”->图片…...

计算机毕业设计 基于SpringBoot的图书馆管理系统的设计与实现 Java实战项目 附源码+文档+视频讲解

博主介绍&#xff1a;✌从事软件开发10年之余&#xff0c;专注于Java技术领域、Python人工智能及数据挖掘、小程序项目开发和Android项目开发等。CSDN、掘金、华为云、InfoQ、阿里云等平台优质作者✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精…...

第三章:最新版零基础学习 PYTHON 教程(第十二节 - Python 运算符—Python 中的运算符函数 - 套装1)

Python 在“operator”模块下预定义了许多数学、逻辑、关系、位等运算的函数。本文介绍了一些基本功能。 1. add(a, b):- 该函数返回给定参数的加法。 操作-a +b。 2. sub(a, b):- 该函数返回给定参数的差值。 操作-a -b。 3. mul(a, b):- 该函数返回给定参数的乘积。 操…...

AAD基础知识(identity/token/PRT)

简介 AAD(Azure Active Directory/Azure AD)是微软基于云身份验证和访问控制的解决方案&#xff0c;通过SSO登录其他o365应用(word/outlook/teams…) 微软在2023年7月把AAD重命名为Microsoft Entra ID&#xff0c;官网&#xff1a;https://www.microsoft.com/zh-cn/security/b…...

基于SSM的视频点播系统设计与实现

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;SSM 前端&#xff1a;采用Vue技术开发 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xff1a;IDEA / Eclipse 是否Maven项目&#x…...

React 知识点总结

本篇文章是我自己总结已经写过的react知识点&#xff0c;大框架已生成&#xff0c;知识持续更新中。仅供参考 生命周期 React 生命周期 组件基础 react中受控组件与非受控组件 React Portals 理解React页面渲染原理&#xff0c;如何优化React性能&#xff1f; 学习篇之R…...

ALSA project the C library refrerenc (ALSA工程 C库参考说明)

作者: Jaroslav Kysela perexperex.cz Abramo Bagnara abramoalsa-project.org Takashi Iwai tiwaisuse.de Frank van de Pol fvdpolcoil.demon.nl前言: 高级linux音频架构(ALSA)来自内核API和库的API.这个篇文章描述了应用层库API和内核层API对应是怎么的interfaces.API用法: …...

【Maven基础篇-黑马程序员】Maven项目管理从基础到高级,一次搞定!

文章目录 前言Maven简介Maven是什么Maven的作用 Maven的下载与安装Maven基础概念仓库坐标仓库配置全局setting与用户setting区别 第一个Maven程序&#xff08;手工制作&#xff09;第一个Maven程序&#xff08;IDEA生成&#xff09;使用模版&#xff08;骨架&#xff09;创建Ma…...

MySQL进阶 —— 超详细操作演示!!!(下)

MySQL进阶 —— 超详细操作演示&#xff01;&#xff01;&#xff01;&#xff08;下&#xff09; 五、锁5.1 概述5.2 全局锁5.3 表级锁5.4 行级锁 六、InnoDB 引擎6.1 逻辑存储结构6.2 架构6.3 事务原理6.4 MVCC 七、MySQL 管理7.1 系统数据库7.2 常用工具 MySQL— 基础语法大…...

SVM(上):如何用一根棍子将蓝红两色球分开?

⭐️⭐️⭐️⭐️⭐️欢迎来到我的博客⭐️⭐️⭐️⭐️⭐️ 🐴作者:秋无之地 🐴简介:CSDN爬虫、后端、大数据领域创作者。目前从事python爬虫、后端和大数据等相关工作,主要擅长领域有:爬虫、后端、大数据开发、数据分析等。 🐴欢迎小伙伴们点赞👍🏻、收藏⭐️、…...

libevent源码学习笔记

libevent源码学习笔记 libevent安装libevent源码解析&#xff08;1&#xff09;事件对象&#xff08;2&#xff09;事件操作&#xff08;3&#xff09;事件循环&#xff08;4&#xff09;事件处理 常用指令问题记录问题一&#xff1a;长连接的管理问题二&#xff1a;连接关闭问…...

Python爬虫实战:研究MechanicalSoup库相关技术

一、MechanicalSoup 库概述 1.1 库简介 MechanicalSoup 是一个 Python 库,专为自动化交互网站而设计。它结合了 requests 的 HTTP 请求能力和 BeautifulSoup 的 HTML 解析能力,提供了直观的 API,让我们可以像人类用户一样浏览网页、填写表单和提交请求。 1.2 主要功能特点…...

什么是库存周转?如何用进销存系统提高库存周转率?

你可能听说过这样一句话&#xff1a; “利润不是赚出来的&#xff0c;是管出来的。” 尤其是在制造业、批发零售、电商这类“货堆成山”的行业&#xff0c;很多企业看着销售不错&#xff0c;账上却没钱、利润也不见了&#xff0c;一翻库存才发现&#xff1a; 一堆卖不动的旧货…...

大模型多显卡多服务器并行计算方法与实践指南

一、分布式训练概述 大规模语言模型的训练通常需要分布式计算技术,以解决单机资源不足的问题。分布式训练主要分为两种模式: 数据并行:将数据分片到不同设备,每个设备拥有完整的模型副本 模型并行:将模型分割到不同设备,每个设备处理部分模型计算 现代大模型训练通常结合…...

Android 之 kotlin 语言学习笔记三(Kotlin-Java 互操作)

参考官方文档&#xff1a;https://developer.android.google.cn/kotlin/interop?hlzh-cn 一、Java&#xff08;供 Kotlin 使用&#xff09; 1、不得使用硬关键字 不要使用 Kotlin 的任何硬关键字作为方法的名称 或字段。允许使用 Kotlin 的软关键字、修饰符关键字和特殊标识…...

AI病理诊断七剑下天山,医疗未来触手可及

一、病理诊断困局&#xff1a;刀尖上的医学艺术 1.1 金标准背后的隐痛 病理诊断被誉为"诊断的诊断"&#xff0c;医生需通过显微镜观察组织切片&#xff0c;在细胞迷宫中捕捉癌变信号。某省病理质控报告显示&#xff0c;基层医院误诊率达12%-15%&#xff0c;专家会诊…...

Mysql8 忘记密码重置,以及问题解决

1.使用免密登录 找到配置MySQL文件&#xff0c;我的文件路径是/etc/mysql/my.cnf&#xff0c;有的人的是/etc/mysql/mysql.cnf 在里最后加入 skip-grant-tables重启MySQL服务 service mysql restartShutting down MySQL… SUCCESS! Starting MySQL… SUCCESS! 重启成功 2.登…...

【 java 虚拟机知识 第一篇 】

目录 1.内存模型 1.1.JVM内存模型的介绍 1.2.堆和栈的区别 1.3.栈的存储细节 1.4.堆的部分 1.5.程序计数器的作用 1.6.方法区的内容 1.7.字符串池 1.8.引用类型 1.9.内存泄漏与内存溢出 1.10.会出现内存溢出的结构 1.内存模型 1.1.JVM内存模型的介绍 内存模型主要分…...

在golang中如何将已安装的依赖降级处理,比如:将 go-ansible/v2@v2.2.0 更换为 go-ansible/@v1.1.7

在 Go 项目中降级 go-ansible 从 v2.2.0 到 v1.1.7 具体步骤&#xff1a; 第一步&#xff1a; 修改 go.mod 文件 // 原 v2 版本声明 require github.com/apenella/go-ansible/v2 v2.2.0 替换为&#xff1a; // 改为 v…...

【java面试】微服务篇

【java面试】微服务篇 一、总体框架二、Springcloud&#xff08;一&#xff09;Springcloud五大组件&#xff08;二&#xff09;服务注册和发现1、Eureka2、Nacos &#xff08;三&#xff09;负载均衡1、Ribbon负载均衡流程2、Ribbon负载均衡策略3、自定义负载均衡策略4、总结 …...

Java多线程实现之Runnable接口深度解析

Java多线程实现之Runnable接口深度解析 一、Runnable接口概述1.1 接口定义1.2 与Thread类的关系1.3 使用Runnable接口的优势 二、Runnable接口的基本实现方式2.1 传统方式实现Runnable接口2.2 使用匿名内部类实现Runnable接口2.3 使用Lambda表达式实现Runnable接口 三、Runnabl…...