web架构师编辑器内容-创建业务组件和编辑器基本行为

编辑器主要分为三部分,左侧是组件模板库,中间是画布区域,右侧是面板设置区域。
左侧是预设各种组件模板进行添加
中间是使用交互手段来更新元素的值
右侧是使用表单的方式来更新元素的值。
大致效果:
在这里插入图片描述

  1. 左侧组件模板库
    最初的模板配置:
export const defaultTextTemplates = [{text: '大标题',fontSize: '30px',fontWeight: 'bold',tag: 'h2'},{text: '楷体副标题',fontSize: '20px',fontWeight: 'bold',fontFamily: '"KaiTi","STKaiti"',tag: 'h2'},{text: '正文内容',tag: 'p'},{text: '宋体正文内容',tag: 'p',fontFamily: '"SimSun","STSong"'},{text: 'Arial style',tag: 'p',fontFamily: '"Arial", sans-serif'},{text: 'Comic Sans',tag: 'p',fontFamily: '"Comic Sans MS"'},{text: 'Courier New',tag: 'p',fontFamily: '"Courier New", monospace'},{text: 'Times New Roman',tag: 'p',fontFamily: '"Times New Roman", serif'},{text: '链接内容',color: '#1890ff',textDecoration: 'underline',tag: 'p'},{text: '按钮内容',color: '#ffffff',backgroundColor: '#1890ff',borderWidth: '1px',borderColor: '#1890ff',borderStyle: 'solid',borderRadius: '2px',paddingLeft: '10px',paddingRight: '10px',paddingTop: '5px',paddingBottom: '5px',width: '100px',tag: 'button',textAlign: 'center'}
]

在component-list组件中循环渲染这个模板
compnent-list组件:

<divclass="component-item"v-for="(item, index) in props.list"@click="onItemClick(item)":key="index"
><LText v-bind="item"></LText>
</div>// LText组件
<component class="l-text-component" :is="props.tag" :style="styleProps" @click="handleClick">{{ props.text }}
</component>
  1. 中间画布区
    基本的数据结构
export interface ComponentData {props: { [key: string]: any }id: stringname: string
}

在左侧模板区域点击的时候,会emit一个onItemCreated事件:

const onItemCreated = (props: ComponentData) => {store.commit('addComponent', props)
}

store里面的addComponent方法:

addComponent(state, props) {const newComponent: ComponentData =id: uuidv4(),name: 'l-text',props}state.components.push(newComponent)
},

渲染中间画布区域:

<div v-for="component in components" :key="component.id"><EditWrapper v-if="!component.isHidden":id="component.id"@set-active="setActive":active="component.id === (currentElement && currentElement.id)" :props="component.props"><component :is="canvasComponentList[component.name as 'l-text' | 'l-image' | 'l-shape']" v-bind="component.props" :isEditing="true"/></EditWrapper></div>

editWrapper组件就是为了隔离两个组件,方便后续的一些拖拽,拉伸,吸附的一些效果。

<template>
<div class="edit-wrapper" @click="itemClick"@dblclick="itemEdit"ref="editWrapper":class="{active: active}" :style="styleProps":data-component-id="id"
> <!-- 元素的扩大 --><div class="move-wrapper" ref="moveWrapper" @mousedown="startMove"><slot></slot></div><div class='resizers'><div class='resizer top-left' @mousedown="startResize($event, 'top-left')"></div><div class='resizer top-right'  @mousedown="startResize($event, 'top-right')"></div><div class='resizer bottom-left' @mousedown="startResize($event, 'bottom-left')"></div><div class='resizer bottom-right' @mousedown="startResize($event, 'bottom-right')"></div></div>
</div>
</template>
  1. 右侧设置面板区域的渲染:
    在中间画布区域进行点击的时候,通过setActive事件,我们可以拿到当前的元素,
// store中的setActive
setActive(state, currentId: string) {state.currentElement = currentId;
},

然后就可以通过props-table组件进行渲染了:

<PropsTable v-if="currentElement && currentElement.props" :props="currentElement.props"@change="handleChange"
></PropsTable>

props-table比较麻烦我们来一一讲解,首先来看一下props-talbe的template部分:

<template><div class="props-table"><divv-for="(value, key) in finalProps":key="key":class="{ 'no-text': !value.text }"class="prop-item":id="`item-${key}`"><span class="label" v-if="value.text">{{ value.text }}</span><div :class="`prop-component component-${value.component}`"><component:is="value.component":[value.valueProp]="value.value"v-bind="value.extraProps"v-on="value.events"><template v-if="value.options"><component:is="value.subComponent"v-for="(option, k) in value.options":key="k":value="option.value"><render-vnode :vNode="option.text"></render-vnode></component></template></component></div></div></div>
</template>

我们最终渲染的是finalProps这个数据,finalProps数据的生成:

// 属性转化成表单的映射表 key:属性  value:使用的组件
export const mapPropsToForms: PropsToForms = {// 比如: text 属性,使用 a-input 这个组件去编辑text: {text: '文本',component: 'a-input',afterTransform: (e: any) => e.target.value,},fontSize: {text: '字号',component: 'a-input-number',// 为了适配类型,进行一定的转换initalTransform: (v: string) => parseInt(v),afterTransform: (e: number) => e ? `${e}px` : '',},lineHeight: {text: '行高',component: 'a-slider',extraProps: {min: 0,max: 3,step: 0.1},initalTransform: (v: string) => parseFloat(v)},textAlign: {component: 'a-radio-group',subComponent: 'a-radio-button',text: '对齐',options: [{value: 'left',text: '左'},{value: 'center',text: '中'},{value: 'right',text: '右'}],afterTransform: (e: any) => e.target.value},fontFamily: {component: 'a-select',subComponent: 'a-select-option',text: '字体',options: [{value: '',text: '无'},...fontFamilyOptions],afterTransform: (e: any) => e},color: {component: 'color-pick',text: '字体颜色',afterTransform: (e: any) => e}
}
const finalProps = computed(() => {// reduce是使用loadsh里面的return reduce(props.props,(result, value, key) => {const newKey = key as keyof AllComponentProps;const item = mapPropsToForms[newKey];if (item) {// v-model默认绑定的值,是value,可以自定义// v-model双向数据绑定的事件,默认是change事件,也可以自定义// initalTransform编辑前的value转换,为了适配类型,进行一定的转换// afterTransform 处理上双向数据绑定后的值。const {valueProp = 'value',eventName = 'change',initalTransform,afterTransform,} = item;const newItem: FormProps = {...item,value: initalTransform ? initalTransform(value) : value,valueProp,eventName,events: {[eventName]: (e: any) => {context.emit('change', {key,value: afterTransform ? afterTransform(e) : e,});},},};result[newKey] = newItem;}return result;},{} as { [key: string]: FormProps });
});

我们传递的props值是这样的:
在这里插入图片描述
最终转换成出来的值是这样的
在这里插入图片描述
在这里插入图片描述
当组件内的change事件改变后,组件内部会触发

context.emit('change', { key, value: afterTransform ? afterTransform(e) : e,});

在父组件中接收change事件来改变stroe中的compoents的值

const handleChange = (e) => {console.log('event', e);store.commit('updateComponent', e)
}

在store中改变components属性

updateComponent(state, { id, key, value, isProps}) {const updatedComponent = state.components.find((component) => component.id === (id || state.currentElement)) as anyif(updatedComponent) {updatedComponent.props[key as keyof TextComponentProps] = value;}
}

难点:

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

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

相关文章

微前端样式隔离、sessionStorage、localStorage隔离

1、样式隔离 前端样式不隔离&#xff0c;会产生样式冲突的问题&#xff0c;这个点在qiankun也存在 子应用1修改一个样式 button {background: red&#xff01;important&#xff1b; }其它应用也会受到影响 qiankun的css隔离方案&#xff08;shadow dom&#xff09; shadow …

FCIS 2023网络安全创新大会-核心PPT资料下载

一、峰会简介 本次会议的主题是“AI大模型、人工智能与智能制造安全、攻击面管理与供应链安全”。 1、AI大模型 会议首先探讨了AI大模型在网络安全领域的应用。AI大模型是一种基于深度学习的模型&#xff0c;具有强大的特征提取和分类能力&#xff0c;可以用于检测和防御各种…

MFC 自定义压缩,解压缩工具

界面效果如下&#xff1a; 对外提供的接口如下&#xff1a; public: void setCallback(zp::Callback callback, void* param); bool open(const zp::String& path, bool readonly false); bool create(const zp::String& path, const zp::String& inputPath)…

代码图形注释自动生成(通过文字图像)

0. 简介 大家在学&#xff08;CTRL&#xff09;习&#xff08;C&#xff09;别人代码的时候&#xff0c;看到别人的代码程序&#xff0c;在日志中有很多很酷的代码注释&#xff0c;或者是有一些图形化注释方便理解。之前本人以为都是一个个手敲出来的。然后在网上一番搜索&…

STM32G4x FLASH 读写配置结构体(LL库下使用)

主要工作就是把HAL的超时用LL库延时替代&#xff0c;保留了中断擦写模式、轮询等待擦写&#xff0c;我已经验证了部分。 笔者用的芯片为STM32G473CBT6 128KB Flash&#xff0c;开环环境为CUBEMXMDK5.32&#xff0c;因为G4已经没有标准库了&#xff0c;笔者还是习惯使用标准库的…

Ubuntu 常用命令之 fdisk 命令用法介绍

&#x1f4d1;Linux/Ubuntu 常用命令归类整理 fdisk 是一个用于处理磁盘分区的命令行工具&#xff0c;它在 Linux 系统中广泛使用。fdisk 命令可以创建、删除、更改、复制和显示硬盘分区&#xff0c;以及更改硬盘的分区 ID。 fdisk 命令的常用参数如下 -l&#xff1a;列出所…

threejs中修改鼠标cursor不生效的问题修复

需求&#xff1a; 当鼠标hover一个元素时&#xff0c;cursor为自定义的图标 问题描述&#xff1a; threejs中修改canvas的鼠标cursor为自定义的图标不生效。 问题原因&#xff1a; 引入了dragcontrols&#xff0c;查看dragControls的代码&#xff0c;可以看到代码中有对cur…

鸿蒙ArkTS语言介绍与TS基础语法

1、ArkTS介绍 ArkTS是HarmonyOS主力应用开发语言&#xff0c;它在TS基础上&#xff0c;匹配ArkUI框架&#xff0c;扩展了声明式UI、状态管理等响应的能力&#xff0c;让开发者以更简洁、更自然的方式开发跨端应用。 JS 是一种属于网络的高级脚本语言&#xff0c;已经被广泛用…

数学建模学习笔记-皮尔逊相关系数

内容&#xff1a;皮尔逊相关系数 一.概念&#xff1a;是一个和线性线关的相关性系数 1.协方差概念&#xff1a; 协方差受到量纲的影响因此需要剔除 2.相关性的误区 根据这个结论&#xff0c;我们在计算该系数之前需要确定是否为线性函数 二.相关性的计算 1.Matlab&#xff…

关于Triple DES(3DES)对称加密算法

一、引言 在网络安全领域&#xff0c;对称加密算法作为一种常见的加密手段&#xff0c;被广泛应用于保障数据传输的保密性和完整性。其中&#xff0c;DES&#xff08;Data Encryption Standard&#xff09;算法作为一种经典的对称加密算法&#xff0c;由IBM于1970年代开发&…

solidity 重入漏洞

目录 1. 重入漏洞的原理 2. 重入漏洞的场景 2.1 msg.sender.call 转账 2.2 修饰器中调用地址可控的函数 1. 重入漏洞的原理 重入漏洞产生的条件&#xff1a; 合约之间可以进行相互间的外部调用 恶意合约 B 调用了合约 A 中的 public funcA 函数&#xff0c;在函数 funcA…

jar混淆,防止反编译,Allatori工具混淆jar包

文章目录 Allatori工具简介下载解压配置config.xml注意事项 Allatori工具简介 官网地址&#xff1a;https://allatori.com/ Allatori不仅混淆了代码&#xff0c;还最大限度地减小了应用程序的大小&#xff0c;提高了速度&#xff0c;同时除了你和你的团队之外&#xff0c;任何人…

持续集成交付CICD:基于ArgoCD 的GitOps 自动化完成前端项目应用发布与回滚

目录 一、实验 1. 环境 2. K8S master节点部署Argo CD 3.基于ArgoCD 实现GitOps &#xff08;同步部署文件&#xff09; 4.基于ArgoCD 实现GitOps &#xff08;同步HELM文件&#xff09; 二、问题 1. ArgoCD 连接K8S集群状态为 Unknown 2.ArgoCD 创建application失败 …

小鹅通基于 TSE 云原生 API 网关的落地实践

导语 2023腾讯全球数字生态大会已于9月7-8日完美落幕&#xff0c;40专场活动展示了腾讯最新的前沿技术、核心产品、解决方案。 微服务与消息队列专场&#xff0c;我们邀请到了小鹅通的基础架构组负责人黄徐震为我们带来了《小鹅通基于 TSE 云原生网关的落地实践》的精彩演讲。…

【K8s】1# 使用kuboard-spray安装K8s集群

文章目录 搭建k8s集群1.推荐配置1.1.服务器配置1.2.软件版本 2.使用Kuboard-Spray安装k8s集群2.1.配置要求2.2.操作系统兼容性2.3.安装 Kuboard-Spray2.4.加载离线资源包2.5.规划并安装集群2.6.安装成功2.7.访问集群 3.涉及的命令3.1.linux 4.问题汇总Q1&#xff1a;启动离线集…

java八股jvm

JVM虚拟机篇-01-JVM介绍、运行流程_哔哩哔哩_bilibili 1.PC程序计数器 2.堆 3.虚拟机栈 4.方法区/永久代/元空间 5.直接内存 JVM虚拟机篇-06-JVM组成-你听过直接内存吗_哔哩哔哩_bilibili 6.双亲委派 从下往上找&#xff0c;有同名类优先使用上级加载器的&#xff0c;不用自…

anconda常用命令

一、基础指令说明 1、查看anconda版本号 conda --version 2、查看当前已有虚拟环境 conda env list 3、创建新环境 conda create -n classify python3.9 创建一个叫做classify的虚拟环境&#xff0c;其中python等于3.9 4、进入虚拟环境 activate classify 5、安装包 接下来…

微软官方镜像下载大全(windows iso 官方镜像)

原本只是想下一个Windows Server 2022中文版的镜像&#xff0c;后面发现要么就是慢得一批的某盘&#xff0c;要么就是磁力&#xff0c;我想直接下载简简单单&#xff0c;找了一圈没有找到。官网下载需要注册、登录乱七八糟&#xff0c;最终终于找到下载方法了&#xff0c;适用于…

DRF之引入

目录 一、web应用模式 【1】前后端混合开发 【2】前后端分离 二、API接口 三、接口测试工具&#xff1a;Postman 四、RESTful API规范 【1】什么是RESTful 【2】RESTful API的规范 2.1 数据的安全保障 2.2 接口特征表现 2.3 多数据版本共存 2.4 数据即是资源&#…

Ubuntu 常用命令之 top 命令用法介绍

&#x1f4d1;Linux/Ubuntu 常用命令归类整理 top命令是Linux下常用的性能分析工具&#xff0c;可以实时动态地查看系统中各个进程的资源占用状况&#xff0c;类似于Windows的任务管理器。它可以显示系统总的和分区的CPU使用率、内存使用率、交换区使用率、系统负载、进程数、…