从零搭建一款PC页面编辑器PC-Dooring

徐小夕
• 阅读 1525

之前一直忙着调研lowcode平台和开发以下两个项目:

没有太多时间做PC端搭建化项目, 好在搭建平台很多原理都是通用的, 所以早在去年我就开发好了面向PC端的编辑器PC-Dooring, 虽然在设计上还有些不足(在后面的内容中会提到) , 但是基本模型已经实现, 接下来就和大家一起分享一下具体的实现.

为了保证文章整体的逻辑性和条理性, 我将可视化搭建平台的具体的实现划分为了以下几个部分:

  • PC编辑器效果展示
  • 整体技术架构
  • 可视化搭建技术实现方式
  • 编辑器核心思路
  • 编辑器架构模型
  • 如何开发标准物料组件
  • 编辑器后期规划

PC编辑器效果展示

从零搭建一款PC页面编辑器PC-Dooring

在上面的演示中, 组件库方式和H5-Dooring类似, 只不过组件库笔者采用了PC端专属的组件库antd, 所以我们可以将antd支持的任何组件集成进PC-Dooring.

整体技术架构

整体技术架构和H5-Dooring类非常相似, 也是遵循笔者的产品设计哲学—— 不要让用户思考. 降低一切拖拽复杂度, 采用智能网格的交互模式来实现(这种设计方式有一定的局限, 仅供大家参考, 当然也可以使用V6.Dooring的自由布局模式). 整体架构如下图所示:

从零搭建一款PC页面编辑器PC-Dooring

由上图我们可以看出编辑器主要分为如下几个部分:

  • 组件物料
  • 画布区
  • 属性编辑区
  • 功能辅助
  • 其他

目前组件物料主要实现了基础组件, 可视化组件媒体组件, 其他类的组件实现也类似, 技术整体实现我们会在下面介绍.

可视化搭建技术实现方式

从零搭建一款PC页面编辑器PC-Dooring

前端框架我们还是使用的React, 当然大家也可以使用Vue3.0, 原理都是相通的, 不同插件之间也提供了多框架的支持. 编辑器核心的一环就是组件拖拽, 这里笔者使用了社区比较强大且稳定的库react-dnd, 其拖拽分为两个部分, 一个是从组件区拖拽到画布区, 另一个是画布区内部组件的自由拖拽. 我们可以用原生H5的拖放API来实现第一部分的功能, 本质是将拖动源携带的数据传到画布制定区域, 目标源监听事件拿到携带的数据动态渲染出实际的组件. 过程如下:

从零搭建一款PC页面编辑器PC-Dooring

当然深入研究过react-dnd的朋友都知道, 以上两个功能通过react-dnd都可以实现, 大家可以参考它的官网react-dnd官网学习研究具体实现流程, 也可以直接参考PC-Dooring源码.

至于组件库, 我们可以采用任何我们熟悉的组件库, 比如antd, element, zant等, 组件物料需要遵循我们约定的DSL协议, 这里大家可以参考工业级协议标准odata规范. 有了一定的规范, 我们就可以包装标准的组件物料从而集成第三方组件库了.

至于功能辅助模块和状态管理, 我们可以采用如mobx, redux, dva等来实现, 最终目的就是让编辑器不同部分能相互关联, 实时更新组件状态, 以及数据回传能力.

编辑器核心思路

编辑器核心实现思路笔者之前也分析了几个现有方案, 发现字节魔方的思路很贴切, 这里附上一个原理图:

从零搭建一款PC页面编辑器PC-Dooring

核心就是通过编辑器产生的有效词法数据, 让渲染器能解析渲染成可用的HTML页面.

编辑器整体架构模型

编辑器整体架构模型主要是为了让大家全局的了解可视化编辑器的实现思路, 以及未来的规划方向, 笔者做了一个基本的草图, 如下:

从零搭建一款PC页面编辑器PC-Dooring

如何开发标准物料组件

开发标准组件物料需要遵循我们编辑器内部的数据协议和组件开发规范, 在PC-Dooring中开发组件主要由以下几部分组成:

  • 组件代码
  • schema定义
  • template定义

组件代码就是组件内部具体的实现, 如下案例:

import React, { memo } from 'react';
import { ITextConfig } from './schema';
import logo from '@/assets/text.png';
const Text = memo((props: ITextConfig & { isTpl: boolean }) => {
  const { align, text, fontSize, color, lineHeight, isTpl } = props;
  return (
    <>
      {isTpl ? (
        <div>
          <img src={logo} alt=""></img>
        </div>
      ) : (
        <div style={{ color, textAlign: align, fontSize, lineHeight }}>{text}</div>
      )}
    </>
  );
});
export default Text;

schema定义了组件的属性约束, 可编辑项类型以及默认值, 如下:

import {
  IColorConfigType,
  INumberConfigType,
  ISelectConfigType,
  ITextConfigType,
  TColorDefaultType,
  TNumberDefaultType,
  TSelectDefaultType,
  TTextDefaultType,
} from '@/components/FormComponents/types';

export type TTextSelectKeyType = 'left' | 'right' | 'center';
export type TTextEditData = Array<
  ITextConfigType | IColorConfigType | INumberConfigType | ISelectConfigType<TTextSelectKeyType>
>;
export interface ITextConfig {
  text: TTextDefaultType;
  color: TColorDefaultType;
  fontSize: TNumberDefaultType;
  align: TSelectDefaultType<TTextSelectKeyType>;
  lineHeight: TNumberDefaultType;
}

export interface ITextSchema {
  editData: TTextEditData;
  config: ITextConfig;
}
const Text: ITextSchema = {
  editData: [
    {
      key: 'text',
      name: '文字',
      type: 'Text',
    },
    {
      key: 'color',
      name: '标题颜色',
      type: 'Color',
    },
    {
      key: 'fontSize',
      name: '字体大小',
      type: 'Number',
    },
    {
      key: 'align',
      name: '对齐方式',
      type: 'Select',
      range: [
        {
          key: 'left',
          text: '左对齐',
        },
        {
          key: 'center',
          text: '居中对齐',
        },
        {
          key: 'right',
          text: '右对齐',
        },
      ],
    },
    {
      key: 'lineHeight',
      name: '行高',
      type: 'Number',
    },
  ],
  config: {
    text: '我是文本',
    color: 'rgba(60,60,60,1)',
    fontSize: 18,
    align: 'center',
    lineHeight: 2,
  },
};
export default Text;

template主要规定了组件在画布中展示的基本方式, 如下:

const template = {
  type: 'Text',
  h: 20,
  displayName: '文本组件',
};
export default template;

当然大家也可以扩展其定义或者将schematemplate合并. 只要一个组件符合了以上约定, 都可以被我们编辑器所消费.

编辑器后期规划

PC编辑器目前仍存在一些问题没有很好的解决, 比如布局方式的局限性导致必须横向扩展很多组件才能满足不同用户的个性化需求, 其次就是组件联动机制, 需要统一数据中心来管理, 后面会在H5-Dooring 中展示具体的实现方式, 大家感兴趣也可以实现一下.

目前PC-Dooring已经在github上以MIT协议完全开源, 如果大家感兴趣,也可以贡献你的一份力量, 帮助社区解决更多问题.

觉得有用 ?喜欢就收藏,顺便点个赞吧,你的支持是我最大的鼓励!微信搜 “趣谈前端”,发现更多有趣的H5游戏, webpack,node,gulp,css3,javascript,nodeJS,canvas数据可视化等前端知识和实战.

点赞
收藏
评论区
推荐文章
秃头王路飞 秃头王路飞
4个月前
webpack5手撸vue2脚手架
webpack5手撸vue相信工作个12年的小伙伴们在面试的时候多多少少怕被问到关于webpack方面的知识,本菜鸟最近闲来无事,就尝试了手撸了下vue2的脚手架,第一次发帖实在是没有经验,望海涵。languageJavaScript"name":"vuecliversion2","version":"1.0.0","desc
浅梦一笑 浅梦一笑
4个月前
初学 Python 需要安装哪些软件?超级实用,小白必看!
编程这个东西是真的奇妙。对于懂得的人来说,会觉得这个工具是多么的好用、有趣,而对于小白来说,就如同大山一样。其实这个都可以理解,大家都是这样过来的。那么接下来就说一下python相关的东西吧,并说一下我对编程的理解。本人也是小白一名,如有不对的地方,还请各位大神指出01名词解释:如果在编程方面接触的比较少,那么对于软件这一块,有几个名词一定要了解,比如开发环
技术小男生 技术小男生
4个月前
linux环境jdk环境变量配置
1:编辑系统配置文件vi/etc/profile2:按字母键i进入编辑模式,在最底部添加内容:JAVAHOME/opt/jdk1.8.0152CLASSPATH.:$JAVAHOME/lib/dt.jar:$JAVAHOME/lib/tools.jarPATH$JAVAHOME/bin:$PATH3:生效配置
光头强的博客 光头强的博客
4个月前
Java面向对象试题
1、请创建一个Animal动物类,要求有方法eat()方法,方法输出一条语句“吃东西”。创建一个接口A,接口里有一个抽象方法fly()。创建一个Bird类继承Animal类并实现接口A里的方法输出一条有语句“鸟儿飞翔”,重写eat()方法输出一条语句“鸟儿吃虫”。在Test类中向上转型创建b对象,调用eat方法。然后向下转型调用eat()方
刚刚好 刚刚好
4个月前
css问题
1、在IOS中图片不显示(给图片加了圆角或者img没有父级)<div<imgsrc""/</divdiv{width:20px;height:20px;borderradius:20px;overflow:h
blmius blmius
1年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
小森森 小森森
4个月前
校园表白墙微信小程序V1.0 SayLove -基于微信云开发-一键快速搭建,开箱即用
后续会继续更新,敬请期待2.0全新版本欢迎添加左边的微信一起探讨!项目地址:(https://www.aliyun.com/activity/daily/bestoffer?userCodesskuuw5n)\2.Bug修复更新日历2.情侣脸功能大家不要使用了,现在阿里云的接口已经要收费了(土豪请随意),\\和注意
晴空闲云 晴空闲云
4个月前
css中box-sizing解放盒子实际宽高计算
我们知道传统的盒子模型,如果增加内边距padding和边框border,那么会撑大整个盒子,造成盒子的宽度不好计算,在实务中特别不方便。boxsizing可以设置盒模型的方式,可以很好的设置固定宽高的盒模型。盒子宽高计算假如我们设置如下盒子:宽度和高度均为200px,那么这会这个盒子实际的宽高就都是200px。但是当我们设置这个盒子的边框和内间距的时候,那
艾木酱 艾木酱
3个月前
快速入门|使用MemFire Cloud构建React Native应用程序
MemFireCloud是一款提供云数据库,用户可以创建云数据库,并对数据库进行管理,还可以对数据库进行备份操作。它还提供后端即服务,用户可以在1分钟内新建一个应用,使用自动生成的API和SDK,访问云数据库、对象存储、用户认证与授权等功能,可专
Wesley13 Wesley13
1年前
MySQL查询按照指定规则排序
1.按照指定(单个)字段排序selectfromtable_nameorderiddesc;2.按照指定(多个)字段排序selectfromtable_nameorderiddesc,statusdesc;3.按照指定字段和规则排序selec
helloworld_28799839 helloworld_28799839
4个月前
常用知识整理
Javascript判断对象是否为空jsObject.keys(myObject).length0经常使用的三元运算我们经常遇到处理表格列状态字段如status的时候可以用到vue