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

布局容器处理

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

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

布局组件的放置

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

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

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

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

        怎么实现选中布局组件可以看前面的文章。选中后仓库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拦截处理。

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

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

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

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

相关文章

在jupyter中更改、增加内核

今天在配置llama2的环境&#xff0c;在学院实验室的服务器上面用jupyter&#xff0c;怎么都不会增加内核。今天说一下怎么把创建好的conda环境增加到jupyter列表中。 例如我有个环境叫做llama2&#xff0c;很简单只要两步。 第一步先激活conda环境。 conda activate llama2第…

Python基础语法(1)

目录 一、常量和表达式 二、变量和类型 2.1 变量是什么 2.2 变量的语法 2.2.1 定义变量 2.2.2 使用变量 2.3 变量的类型 2.3.1 整数 2.3.2 浮点数(小数) 2.3.3 字符串 2.3.4 布尔 2.3.5 其他 2.4 为什么要有这么多类型 2.4.1 类型决定了数据在内存中占据多大空间…

如何进行日期和时间的计算和操作?

C语言日期和时间的计算与操作 日期和时间在计算机编程中是非常重要的概念&#xff0c;它们用于各种应用&#xff0c;包括日历应用、计时器、事件调度等。C语言提供了一些标准库函数来处理日期和时间&#xff0c;使得在程序中进行日期和时间的计算和操作变得相对容易。本文将详…

【STM32 CubeMX】移植u8g2(一次成功)

文章目录 前言一、下载u8g2源文件二、复制和更改文件2.1 复制文件2.2 修改文件u8g2_d_setup文件u8g2_d_memory 三、编写oled.c和oled.h文件3.1 CubeMX配置I2C3.2 编写文件oled.holed.c 四、测试代码main函数测试代码 总结 前言 在本文中&#xff0c;我们将介绍如何在STM32上成…

[C++随想录] 优先级队列

优先级队列 基本使用题目训练 基本使用 priority_queue, 优先级队列, 又叫做双端队列, 头文件也是 <queue> 别看它叫做队列, 其实它是一个 堆 补充一下概念: 大根堆 — — 每一棵树的父节点比它的孩子都大小跟堆 — — 每一棵树的父节点比它的孩子都小 &#x1f447;&…

Golang语法、技巧和窍门

Golang简介 命令式语言静态类型语法标记类似于C&#xff08;但括号较少且没有分号&#xff09;&#xff0c;结构类似Oberon-2编译为本机代码&#xff08;没有JVM&#xff09;没有类&#xff0c;但有带有方法的结构接口没有实现继承。不过有type嵌入。函数是一等公民函数可以返…

设计模式10、外观模式Facade

解释说明&#xff1a;外观模式&#xff08;Facade Pattern&#xff09;又称为门面模式&#xff0c;属于结构型模式 Faade 为子系统中的一组接口提供了一个统一的高层接口&#xff0c;该接口使得子系统更加容易使用 外观&#xff08;Facade)角色&#xff1a;为多个子系统对外提供…

Sql注入(手工注入思路、绕过、防御)

一、Sql注入思路 1、判断注入点 在GET参数、POST参数、以及HTTP头部等&#xff0c;包括Cookie、Referer、XFF(X-Forwarded-for)、UA等地方尝试插入代码、符号或语句&#xff0c;尝试是否存在数据库参数读取行为&#xff0c;以及能否对其参数产生影响&#xff0c;如产生影响则…

thymeleaf学习

学习链接 th:fragment fragment的引用 th:insert:保留自己的主标签&#xff0c;保留th:fragment的主标签。 th:replace:不要自己的主标签&#xff0c;保留th:fragment的主标签。 th:include:保留自己的主标签&#xff0c;不要th:fragment的主标签。&#xff08;官方3.0后不推荐…

信创办公–基于WPS的EXCEL最佳实践系列 (数据整理复制粘贴)

信创办公–基于WPS的EXCEL最佳实践系列 &#xff08;数据整理复制粘贴&#xff09; 目录 应用背景操作步骤1、数据查找与替换2、复制或粘贴数据3、使用自动填充工具4、将数据拆分到多列5、应用数字格式 应用背景 数据的整理复制粘贴等在日常的工作中经常使用。本章内容主要学习…

第9章 Mybatis

9.1 谈谈你对Mybatis的理解 难度:★★ 重点:★★ 白话解析 说清楚Mybatis是什么,它的工作流程,然后再对比一下Hibernate就好了。 1、Mybatis是什么:它一个半自动ORM框架,它底层把JDBC那套加载驱动、创建连接、创建statement等重复性的硬编码全部给你封装好了,程序员只…

设计模式 - 享元模式

目录 一. 前言 二. 实现 一. 前言 享元模式&#xff08;Flyweight Pattern&#xff09;是一种结构型设计模式&#xff0c;它主要解决的问题是创建大量相似对象时的内存开销问题。该模式通过共享具有相同状态的对象来减少内存使用量。 享元模式的思想是&#xff1a;当需要创建…

嵌入式Linux应用开发-基础知识-第十九章驱动程序基石③

嵌入式Linux应用开发-基础知识-第十九章驱动程序基石③ 第十九章 驱动程序基石③19.5 定时器19.5.1 内核函数19.5.2 定时器时间单位19.5.3 使用定时器处理按键抖动19.5.4 现场编程、上机19.5.5 深入研究&#xff1a;定时器的内部机制19.5.6 深入研究&#xff1a;找到系统滴答 1…

SpringCloud(一)Eureka、Nacos、Feign、Gateway

文章目录 概述微服务技术对比 Eureka服务远程调用服务提供者和消费者Eureka注册中心搭建注册中心服务注册服务发现Ribbon负载均衡负载均衡策略饥饿加载 NacosNacos与Eureka对比Nacos服务注册Nacos服务分集群存储NacosRule负载均衡服务实例权重设置环境隔离 Nacos配置管理配置热…

ESP32设备驱动-OLED-SSD1306(I2C)显示屏驱动

OLED-SSD1306(I2C)显示屏驱动 1、OLED介绍 OLED显示屏是指有机电激发光二极管(OrganicLight-EmittingDiode,OLED)由于同时具备自发光,不需背光源、对比度高、厚度薄、视角广、反应速度快、可用于挠曲性面板、使用温度范围广、构造及制程较简单等优异之特性,被认为是下一…

C++面试题准备

文章目录 一、线程1.什么是进程&#xff0c;线程&#xff0c;彼此有什么区别?2.多进程、多线程的优缺点3.什么时候用进程&#xff0c;什么时候用线程4.多进程、多线程同步&#xff08;通讯&#xff09;的方法5.父进程、子进程的关系以及区别6.什么是进程上下文、中断上下文7.一…

短期风速预测|LSTM|ELM|批处理(matlab代码)

目录 1 主要内容 LSTM-长短时记忆 ELM-极限学习机 2 部分代码 3 程序结果 4 程序链接 1 主要内容 该程序是预测类的基础性代码&#xff0c;程序对河北某地区的气象数据进行详细统计&#xff0c;程序最终得到pm2.5的预测结果&#xff0c;通过更改数据很容易得到风速预测结…

Java 中的参数传递方式

Java 中的参数传递方式通常被称为“值传递”&#xff0c;这意味着在方法调用时&#xff0c;实际上传递给方法的是变量的副本&#xff0c;而不是变量本身。尽管这被广泛称为“值传递”&#xff0c;但需要注意的是&#xff0c;这并不意味着 Java 不支持引用传递。事实上&#xff…

WSL2安装历程

WLS2安装 1、系统检查 安装WSL2必须运行 Windows 10 版本 2004 及更高版本&#xff08;内部版本 19041 及更高版本&#xff09;或 Windows 11。 查看 Windows 版本及内部版本号&#xff0c;选择 Win R&#xff0c;然后键入winver。 2、家庭版升级企业版 下载HEU_KMS_Activ…

Django模板加载与响应

前言 Django 的模板系统将 Python 代码与 HTML 代码解耦&#xff0c;动态地生成 HTML 页面。Django 项目可以配置一个或多个模板引擎&#xff0c;但是通常使用 Django 的模板系统时&#xff0c;应该首先考虑其内置的后端 DTL&#xff08;Django Template Language&#xff0c;D…