最新要闻
- 热资讯!重庆一景区煮麻辣汤圆:下次元宵佳节还得等384天
- 男子打包螺蛳粉开车24小时运回北京 只因朋友圈一句话:这是真爱
- 【天天新视野】用户滑雪频繁触发iPhone车祸检测功能 苹果:已进行了优化 同时派代表考察
- 天天快播:甜品级游戏本价格已曝光:搭载RTX 4050/4060
- 女子春节连打4通宵麻将:患上突发性耳聋
- 国产显卡搞定“显卡杀手”:摩尔线程MTT S80居然能跑《孤岛危机》
- 【世界独家】极限挤牙膏!三星Galaxy S23系列用残血版LPDDR5X内存
- 【全球热闻】游客洪崖洞花30元找当地大爷抄近道 只花2分钟:网友道出真相
- 速讯:博纳影业总裁妻子金巧巧否认暗指《满江红》排片多、不好看:个人喜好
- 颜值最高的白色手机来了!vivo X90告白下周预售:天玑9200加持
- 零下10度静止一夜不掉电!“车主”盛赞恒驰5 OTA效果好
- 大众也不香了!比亚迪ATTO 3获德媒超高认可:钟爱刀片电池
- 快资讯:CPU性能提升10%!13代酷睿笔记本测试数据出炉
- 【全球报资讯】盖茨向马斯克“泼冷水”:殖民火星完全浪费钱
- 世界新资讯:医生发现19岁阿尔兹海默症患者:已知最年轻
- 环球微头条丨用ChatGPT写作业?新算法给AI生成文本加水印:置信度高达99.999999999994%
手机
iphone11大小尺寸是多少?苹果iPhone11和iPhone13的区别是什么?
警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案
- iphone11大小尺寸是多少?苹果iPhone11和iPhone13的区别是什么?
- 警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案
- 男子被关545天申国赔:获赔18万多 驳回精神抚慰金
- 3天内26名本土感染者,辽宁确诊人数已超安徽
- 广西柳州一男子因纠纷杀害三人后自首
- 洱海坠机4名机组人员被批准为烈士 数千干部群众悼念
家电
低代码平台前端的设计与实现(三)设计态画布DesignCanvas的设计与实现
上一篇文章,我们分析并设计了关于构建引擎BuildEngine的切面设计。本文我们将基于BuildEngine所提供的切面处理能力,在ComponentBuildAspectHandler中通过一些逻辑,来完成一个轻量级的设计器画布。
(资料图片)
这个画布能够实现如下的一个简单的效果。对于所有渲染出来的元素,都会有一个灰色的边框,当我们选中某个元素的时候,就会高亮显示。
ElementNodeDesignWrapper
要做到上述效果,对于通过ElementNode创建出来的组件,我们可以使用一个元素来进行包裹,我们暂时对这个组件取名为ElementNodeDesignWrapper
,它的作用就是能够给每一个元素添加边框。
这个wrapper组件,我们至少会设计以下几个属性:
- nodePath:一个基本信息,作为外部传入;
- isSelected:决定该wrapper是否被选中;
- onClick:wrapper组件被点击时候,触发的onClick事件;
有了isSelected
和onClick
以后,我们就可以让上层代码来控制多个元素究竟是哪个元素需要高亮。
export type ElementNodeDesignWrapperProps = { /** * 标识当前节点path */ nodePath: string; /** * 是否被选中 */ isSelected?: boolean; /** * 点击事件 */ onClick?: () => void;}
对于这个wrapper,我们考虑使用div元素来包裹子元素,也就是说,wrapper的本质是div。这个div元素我们通过isSelected(是否选中)来控制其CSS中的outline
样式配置。之所以选择outline
,是因为outline在显示的时候,是不会影响元素的位置大小的,但缺点则是无论其元素是什么外形,outline
总是矩形。
其次,我们还需要考虑这样一种问题,如果wrapper div包裹的实际HTML是、
、
、
以及
元素,如果我们不将这个作为wrapper div的display设置为
inline-block
,那么wrapper div则会变成宽度占据一行的元素,会变成如下效果:
我们需要做的就是,检测wrapper div内部的元素是button、a、span、b或i元素的时候,则将wrapper div的样式中display属性置为inline-block
,这样wrapper div就可以贴合这些元素。
那么,如何检测呢?我们可以采用这样一种方式:通过useRef这个Hook来创建一个ref,交给我们的wrapper div;然后,在useEffect的回调中,拿到类型为HTMLDivElement的ref.current。这个current我们可以通过访问firstChild就是div的唯一一个子元素,也就是wrapper包裹的元素。并且,我们可以访问firstChild.nodeName就能知道wrapper的HTML元素名称。存放到一个名为targetNodeHtmlType
的state中;最后,我们按照上面的需求,让wrapper div的样式中的display属性,根据targetNodeHtmlType
是否属于button、a、span、b或i元素中的一种来决定是否是inline-block
。
最后,我们还需要对wrapper div的onClick事件进行“代理”,并阻止冒泡。
综合以上的分析,我们Wrapper div最终的样式核心代码:
export const ElementNodeDesignWrapper: FC> = (props) => { const { nodePath, isSelected = false, children, onClick = () => { } } = props; const ref = useRef(null); const [ targetNodeHtmlType, setTargetNodeHtmlType ] = useState(); useEffect(() => { if (!ref || !ref.current) { return; } const currentEle: HTMLDivElement = ref.current; const eleNodeName = currentEle.firstChild.nodeName; setTargetNodeHtmlType(eleNodeName); }); const style: CSSProperties = useMemo(() => { // Wrapper内部以下实际的HTML元素在展示的过程中,需要使用inline-block // 否则会显示异常 const inlineBlockEle = ["A", "SPAN", "BUTTON", "B", "I"]; return { boxSizing: "border-box", // 元素被选中,则使用蓝色高亮边框,否则使用灰色虚线 outline: isSelected ? "2px solid blue" : "1px dashed gray", display: inlineBlockEle.includes(targetNodeHtmlType) ? "inline-block" : "", padding: "3px", margin: "3px" } }, [isSelected, targetNodeHtmlType]); return ( { event.stopPropagation(); onClick(); }}> {children} )}
DesignCanvas
接下来,我们开始设计一个名为DesignCanvas的设计态画布,这个画布我们先暂时先不考虑比较复杂的功能,先考虑如何结合上面的Wrapper组件进行基本的效果呈现。考虑到对外屏蔽DesignCanvas的细节,我们只暴露一个属性,就是传入 JSON schema:
interface DesignCanvasProps { /** * Schema JSON字符串 */ rootNodeSchemaJson: string;}export const DesignCanvas = (props: DesignCanvasProps) => { const { rootNodeSchemaJson } = props; // 1. 存储单机选中的path的state const [selectedNodePath, setSelectedNodePath] = useState(""); // 2. 经过切面绑定的buildEngine const buildEngine = ... ... // 3. 经过buildEngine + schema 创建的React组件(已经考虑的基本的异常处理) const renderComponent = ... ... return ( {renderComponent} )}
(1)selectedNodePath用以存储当前选中的path。在后续的切面处理中,构建元素节点的时候,如果切面正在处理的节点path与selectedNodePath一致,则wrapper组件需要高亮,否则虚线。
(2)buildEngine的代码具体如下:
// 经过切面绑定的buildEngine const buildEngine = useMemo(() => { const engine = new BuildEngine(); engine.componentBuildAspectHandler = (reactNode, ctx) => { const {path} = ctx; const wrapperProps: ElementNodeDesignWrapperProps = { nodePath: path, isSelected: path === selectedNodePath, onClick: () => { console.debug("wrapper onClick") setSelectedNodePath(path) } } return ( {reactNode} ) } return engine; }, [selectedNodePath]);
上面的buildEngine中的componentBuildAspectHandler切面处理,我们编写了我们自己的实现,原本默认返回的组件,我们使用ElementNodeDesignWrapper进行包裹返回。其中:
isSelected属性来自于当前正处理节点path与第1点DesignCanvas组件存储的path的比对,如果当前正在处理及的几点就是已经选中的节点path,那么这个wrapper组件则被“选中”。
onClick属性的实现代码则是当wrapper组件点击后,更新selectedNodePath。
(3)renderComponent的实现:
// 经过buildEngine + schema 创建的React组件(已经考虑的基本的异常处理) const renderComponent = useMemo(() => { try { const eleNode = JSON.parse(rootNodeSchemaJson); return buildEngine.build(eleNode); } catch (e) { return 构建出错:{e.message} } }, [rootNodeSchemaJson, selectedNodePath]);
对于这个渲染React组件,主要是将schema解析为ElementNode结构,并交给构建引擎build;如果报错则返回一个异常组件。
样例
在编写样例之前,我们先导出DesignCanvas,然后适当修改样例代码:
import {ChangeEvent, useState} from "react";import {Input} from "antd";import {DesignCanvas} from "@lite-lc/core";export function SimpleExample() { // 使用state存储一个schema的字符串 const [elementNodeJson, setElementNodeJson] = useState(JSON.stringify({ "type": "page", "props": { "backgroundColor": "pink", // page的 backgroundColor 配置 }, "children": [ { "type": "button", "props": { "size": "blue" // button的size配置 }, }, { "type": "input" } ] }, null, 2)) return ( ) => { const value = e.target.value; // 编辑框发生修改,重新设置JSON setElementNodeJson(value); }}/> );}
效果:
附录
本次相关代码已经提交至github,对应分支为chapter_03:
w4ngzhen/lite-lc at chapter_03 (github.com)
-
低代码平台前端的设计与实现(三)设计态画布DesignCanvas的设计与实现
上一篇文章,我们分析并设计了关于构建引擎BuildEngine的切面设计。本文我们将基于BuildEngine所提供的...
来源: 低代码平台前端的设计与实现(三)设计态画布DesignCanvas的设计与实现
热资讯!重庆一景区煮麻辣汤圆:下次元宵佳节还得等384天
男子打包螺蛳粉开车24小时运回北京 只因朋友圈一句话:这是真爱
【天天新视野】用户滑雪频繁触发iPhone车祸检测功能 苹果:已进行了优化 同时派代表考察
天天快播:甜品级游戏本价格已曝光:搭载RTX 4050/4060
环球消息!5 组合数据类型
今日讯!短记我的二十五岁,如落叶般随风飘荡。
世界观焦点:java基础:流程控制
女子春节连打4通宵麻将:患上突发性耳聋
国产显卡搞定“显卡杀手”:摩尔线程MTT S80居然能跑《孤岛危机》
【世界独家】极限挤牙膏!三星Galaxy S23系列用残血版LPDDR5X内存
世界微动态丨wireshark 抓包整理———— 从一个小案例开始 [一]
【全球热闻】游客洪崖洞花30元找当地大爷抄近道 只花2分钟:网友道出真相
速讯:博纳影业总裁妻子金巧巧否认暗指《满江红》排片多、不好看:个人喜好
颜值最高的白色手机来了!vivo X90告白下周预售:天玑9200加持
天天消息!Python教程:IO
零下10度静止一夜不掉电!“车主”盛赞恒驰5 OTA效果好
当前视点!java基础:java基础语法
大众也不香了!比亚迪ATTO 3获德媒超高认可:钟爱刀片电池
快资讯:CPU性能提升10%!13代酷睿笔记本测试数据出炉
【全球报资讯】盖茨向马斯克“泼冷水”:殖民火星完全浪费钱
世界新资讯:医生发现19岁阿尔兹海默症患者:已知最年轻
SQL SERVER——高可用技术概述
环球微头条丨用ChatGPT写作业?新算法给AI生成文本加水印:置信度高达99.999999999994%
快播:【Redis场景拓展】秒杀问题-全局唯一ID生成策略
美团一面:InndoDB 单表最多 2000W,为什么?小伙伴竟然面挂
每日精选:2个月没人管!AMD老显卡终于要有新驱动了
奢侈品不愁卖!LV将涨价20% 世界首富放言:中国人有钱
全球看热讯:Andlua+实现WakeUpOnline远程开机
Docker搭建本地私有仓库
世界即时:vue/ts 新建项目时好用的配置 【vite.config.ts、tsconfig.json、】
天天热点!大爷看《狂飙》入戏屏幕前举杯痛饮 被演技折服:口碑大剧结尾你满意吗?
厉害!中国半导体领域科研论文数量持续全球第一 光触媒等已超美国
【缓存策略及实践】前端如何配置 HTTP 缓存机制
全球简讯:为什么感觉工资过万很普遍了?打打字就能月入过万你心动吗?央视揭秘新骗局
《生化危机4:重制版》第五章演示:里昂和碍事梨合作通关
云南小女孩骑鸵鸟上学从容淡定 挡眼睛控制方向:网友调侃是大象年检了
观焦点:造车新势力轿车月榜Top2 长安深蓝SL03迎开门红:1月交付6137台
环球快消息!越野车开进古河床随意碾压:改装牧马人无视警示牌“撒野” 专家:保护有难度
天天微资讯!2899元价格屠夫!XiaoMI Book 12.4 二合一评测:办公追剧不在话下
微头条丨C盘扩容:不要轻易转换动态磁盘 Dynamic Disk
乳腺癌已成为全球第一大癌症:我国每年新增42万 比国外发病早
今日观点!投资不过山海关对东北伤害狠!老工业基地全力发展新能源车 专家称沈阳可成深圳
世界今热点:全球首位!以色列总统使用ChatGPT写演讲稿:开头、结尾感受下
全球看热讯:《角斗士2》明年上映
全球热点评!阿里云盘致歉:昨晚系统故障 全平台无法加载内容
TGA年度最佳!《双人成行》销量破1000万:双人游戏天花板
环球今日报丨特斯拉降价到20万出头 网友忍不住要下单 宝马奔驰大众:我们不跟
速递!腾讯视频官宣:《三体》番外剧《三体:大史》即将上线
2023年1月随笔
世界今日报丨大跃进了!今年小米新机都将抛弃USB 2.0
今日立春:二十四节气之首 万物开始复苏
8个你可能不知道答案的常见JavaScript面试问题
世界热资讯!荣耀北斗卫星通信专利获批通过 荣耀Magic5系列将首发?
B站《三体》动画“晚节不保”:即将跌破4分
全球实时:再也不怕手一抖跳广告了!规范App乱跳转新标准出台
热门:坚挺四年的苹果:栽了
关注:你以为你真的会玩《俄罗斯方块》?看完这些大神 我大悟了
UI通过元素定位实现特定区域截图
全球热推荐:2022浙江高考数学导数压轴解析
每日速讯:春节开特斯拉出行的国内车主真不少!自驾万里的数以百计
微头条丨开年如何选购生产力整机!锐龙9 7950X vs i9-13900K对比测试:谁是更好的创作工具?
【全球聚看点】客人泡茶放近50根藏红花吓坏主人 真大补药:喝完身体并没有不适
四川公司回应招聘“下班到点跑的绕道”:本职工作完成不用加班
世界今亮点!MySQL数据类型补充
当前资讯!Python中的关键字的用法
每日热闻!在 FreeBSD 12 上安装 Gitea
女子身高185求职当老师被拒 用人单位:常弯腰工作很累
环球焦点!599元 戴尔上架新款透明机械键盘:定制轴体 全键热插拔
AMD Zen4笔记本登顶世界第一!31%优势碾压12代酷睿
环球最资讯丨ES6 简介(一)
【环球热闻】一汽车电梯故障 200多万的法拉利秒变“大事故车”
NVIDIA AD106、AD107小核心首次现身:“减肥”多达30%
全球今亮点!《狂飙》能“逆风翻盘” 一半功劳都是热搜的
全球微速讯:宠托师职业受青睐!上门喂宠物 几天收入数千元
环球微速讯:不用羡慕代驾小哥了!绿源新品TCR开售:整车超轻能跑120km
100%纯果蔬汁:味全每日C果汁5.5元/瓶抄底
私家车定速巡航失灵!时速120狂飙半小时:万幸平安无事
全球快报:《三体》主演于和伟:我本身就是科幻迷!
环球快看点丨1月新能源汽车销量榜:比亚迪“能打”两个特斯拉
全球快讯:iPhone 14 Plus出货跌到0台:苹果拒绝认输
一文搞懂工作流审批(Java+activiti)快速开发+自定义工作流
天天热推荐:HEU_KMS_Activator_v27.0.2全能系统数字许可激活工具
快看:2999元 联想扬天V14/V15笔记本上架:Zen2架构锐龙5 7520U
国产科幻FPS大作!《边境》官宣2月6日开启新测试
环球焦点!网友花2499元就买到了努比亚Z50:系统零广告 性价比无敌
每日热门:AMD终于要解决锐龙7000装机贵的麻烦了 B650主板降价
每日速递:《三体》电视剧惊现360全家桶产品:竟遭周鸿祎挑刺
天天热讯:大神教你显卡和CPU怎么搭配才合适
Python借助企业微信群机器人推送消息和文件
【天天聚看点】【验证码逆向专栏】某验“初代”滑块验证码逆向分析
快资讯丨阿里二面: BigKey、HotKey 问题严重,该如何 预防和解决
Pandas练习
2023年安卓机皇!聊聊三星S23系列与前代有哪些不同
当前观点:高颜值+顶级做工!铭瑄RTX 4080 iCraft OC16G瑷珈显卡评测:三风扇稳压71℃
全球讯息:奥迪E-Tron撞车 电池包撞飞后起火!官方:不清楚是安全功能还是隐患
天天观热点:投屏480p、禁HDMI被吐槽割韭菜!爱奇艺利润将暴增 外资力挺
全球微速讯:《森林之子》PC配置需求公布 1080Ti显卡就能爽玩
看点:微信对话生成器,生成微信聊天记录,聊天记录生成器
环球快看:跳表java实现(可直接运行)