基于React+Koa实现一个h5页面可视化编辑器

徐小夕 等级 776 0 0

前言

前段时间笔者一直忙于数据可视化方面的工作,比如如何实现拖拽式生成可视化大屏,如何定制可视化图表交互和数据导入方案等,这块需求在B端企业中应用非常大,所以非常有探索价值。

本篇文章并非和数据可视化相关,而是通过抽象技术底层,将其应用于H5页面可视化搭建上,通过技术的手段实现拖拽式生成H5页面。这块也有非常多的应用场景,比如我们需要开发一个移动端网站,一个H5营销页面,H5活动页面等,如果有这样的傻瓜式拖拽的工具生成H5页面,将会极大的提高我们的工作效率。

接下来笔者将对h5页面可视化编辑器-Dooring做详细的项目分析和原理解读,来带大家深入了解h5可视化搭建页面的原理和技术实现。H5编辑器预览如下: 基于React+Koa实现一个h5页面可视化编辑器

github地址:传送门

技术栈

  • React 前端主流框架(react,vue,angular)之一,更适合开发灵活度高且复杂的应用
  • dva 主流的react应用状态管理工具,基于redux
  • less css预编译语言,轻松编写结构化分明的css
  • umi 基于react的前端集成解决方案
  • antd 地球人都知道的react组件库
  • axios 强大的前端请求库
  • react-dnd 基于react的拖拽组件解决方案,具有优秀的设计哲学
  • qrcode.react 基于react的二维码生成插件
  • zarm 基于react的移动端ui库,轻松实现美观的H5应用
  • koa 基于nodejs的上一代开发框架,轻松实现基于nodejs的后端开发
  • @koa/router 基于koa2的服务端路由中间件
  • ramda 优秀的函数式js工具库

需求分析

在思考需求分析之前我们先来看看Dooring的使用演示: 基于React+Koa实现一个h5页面可视化编辑器 由上面的gif图我们可以分析出,可视化编辑器主要有以下几部分组成:

  • 可拖拽的组件库 draggable components
  • 盛放组件的画布 canvas
  • 组件编辑器 FormEditor
  • 头部工具栏 toolBar

可拖拽组件我们可以用社区比较火的react-dndreact-draggable来实现,由于我们的画布是可拖拽可放大缩小的,所以这里需要对画布赋能,具体实现可参考下文。

其次就是H5编辑器部分,这部分是核心功能,后面我们会详细分析。还有就是预览,生成预览链接,保存json文件, 保存模版这些功能本质上是对我们json文件的操作,可是目前可视化搭建技术的常用手段之一。先来看看这些功能的演示: 基于React+Koa实现一个h5页面可视化编辑器

基础准备

我们的h5页面可视化编辑器采用umi来作为脚手架工具.

umi是可扩展的企业级前端应用框架,以路由为基础的,同时支持配置式路由和约定式路由,保证路由的功能完备,并以此进行功能扩展。然后配以生命周期完善的插件体系,覆盖从源码到构建产物的每个生命周期,支持各种功能扩展和业务需求.

这样我们不会关注繁琐的工程配置细节, 可以直接在项目中使用 antdless 这些方案, 并且集成了目前比较流行的css module, 可以方便我们在项目里对css进行模块化开发. umi创建项目的具体使用流程如下:

// 创建并进入工程目录
mkdir dooring && cd dooring
// 创建umi应用
yarn create @umijs/umi-app
// 安装依赖
yarn    // 或者使用npm install

简单的三步走策略就能轻松搭建我们的项目工程, 是不是省去了很多麻烦? (在使用这些方式之前我们首先确保自己本地的node 版本是 10.13 或以上)

在项目搭建完成之后我们调整一下目录结构, 具体如下:

dooring                       
├─ src                        
│  ├─ assets                  
│  │  └─ yay.jpg              
│  ├─ components              
│  ├─ layouts                 
│  │  ├─ __tests__            
│  │  │  └─ index.test.js     
│  │  ├─ index.css            
│  │  └─ index.js             
│  ├─ models                  
│  │  └─ editor.js            
│  ├─ pages                   
│  │  ├─ __tests__            
│  │  │  └─ index.test.js     
│  │  ├─ editor               
│  │  │  ├─ components        
│  │  │  │  └─ FormEditor     
│  │  │  │     ├─ index.js    
│  │  │  │     └─ index.less  
│  │  │  ├─ container.js      
│  │  │  ├─ index.js          
│  │  │  └─ index.less        
│  │  ├─ index.css            
│  │  └─ index.js             
│  ├─ service                  
│  │  └─ editor.js            
│  ├─ app.js                  
│  └─ global.css              
├─ package.json               
└─ webpack.config.js          

page目录下的editor使我们的主页面, components存放我们的公共组件, models和service主要负责处理dva的状态管理逻辑, 其他部分大家可以更具需求自由定义.此处仅供学习参考.

在项目创建完之后我们还需要安装可视化方面必备的第三方组件, 笔者调研社区精选组件之后采用了一下方案:

  • react-dnd react拖拽组件
  • react-color react颜色选择组件,用于H5编辑器的编辑颜色部分
  • react-draggable 用于组件或者画布的拖拽移动
  • react.qrcode 基于react的二维码生成组件, 能以react组件的方式生成二维码

以上组件在运行项目前大家可以自行安装.

正文

在最好项目开发准备之后,我们就来开始设计我们的h5页面可视化编辑器-Dooring.

H5编辑器实现

H5可视化编辑器主要需要4个部分,在文章开头也分析过, 这里用图来巩固一下: 基于React+Koa实现一个h5页面可视化编辑器 以上是最基本也是最核心的功能展示模型,接下来我们会一一将其拆解并逐个实现.

实现原理

我们都知道, 目前比较流行的页面可视化搭建方案可以有如下几种:

  • 在线编辑代码实现
  • 在线编辑json实现
  • 无代码化拖拽实现(底层基于json配置文件)

笔者做了一下优缺点对比图,如下:

方案 定制化程度 缺点
在线编辑代码 最高 使用成本高,对非技术人员不友好,效率低
在线编辑json 较高 需要熟悉json,有一定使用成本, 对非技术人员不友好,效率一般
无代码化拖拽实现 使用成本低, 操作基本无门槛,效率较高

由以上分析来看, 为了开发一个低门槛, 对任何人适用的可视化编辑器, 笔者将采用第三种方案来实现, 目前市面上已有的产品也有很多, 比如说易企秀, 兔展, 百度H5等等. 实现原理其实还是基于json, 我们通过可视化的手段将自己配置的 页面转化为json数据,最后在基于json渲染器来动态生成H5站点. 基于React+Koa实现一个h5页面可视化编辑器

数据结构设计

为了提供组件的自定义能力,我们需要定义一套高可用的数据结构, 这样才能实现因组件需求变更而带来的维护性优势.

在开始设计数据结构之前我们先来拆解一下模块: 基于React+Koa实现一个h5页面可视化编辑器 不同的组件都对应不同的"编辑区域".我们需要设计一套统一的标准的配置来约定它, 这样对于表单编辑器的设计也非常有利, 具体拆解如下: 基于React+Koa实现一个h5页面可视化编辑器

经过以上分析之后, 笔者设计了类似下面的数据结构:

"Text": {
    "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
    }
}

通过这种标准化结构设计之后,我们可以很方便的实现我们所需要的编辑页面的功能, 并且后期扩展非常方便, 只需要往editData添加配置即可. 至于动态表单编辑器的实现,方案有很多, 笔者之前也写过相关的文章, 这里就不详细介绍了.

基于react搭建一个通用的表单管理配置平台(vue同)

组件库设计

组件库设计考虑的一个重要的问题就是体积和渲染问题, 一旦组件库变的越来越多, 那意味着页面加载会非常慢,所以我们需要实现异步加载组件和代码分割的能力, umi提供了这样的功能,我们可以基于它提供的api去实现自己的额按需组件.

import { dynamic } from 'umi';

export default dynamic({
  loader: async function() {
    // 这里的注释 webpackChunkName 可以指导 webpack 将该组件 HugeA 以这个名字单独拆出去
    const { default: HugeA } = await import(/* webpackChunkName: "external_A" */ './HugeA');
    return HugeA;
  },
});

通过以上的方式来定义包裹我们的每一个组件, 这样就能实现按需加载了, 但是最好的建议是不需要每个组件都按需加载和拆包,对于标题, 通知栏,页头,页脚这些组件, 我们完全可以把它放在一个组里,这样不但对不会影响加载速度, 还能减少一定的http请求.

笔者这里简单举一个组件实现的例子,方便大家理解:

const Header = memo((props) => {
  const { 
    bgColor,
    logo,
    logoText,
    fontSize,
    color
  } = props
  return <header className={styles.header} style={{backgroundColor: bgColor}}>
      <div className={styles.logo}>
        <img src={logo && logo[0].url} alt={logoText} />
      </div>
      <div className={styles.title} style={{fontSize, color}}>{ logoText }</div>
  </header>
})

上面的Header组件的props属性完全是由我们之前设计的json结构来定义的,在用户编辑的过程中将收据收集并传给Header组件。最后一步是将这些组件动态传给dynamic组件, 这块在上文也介绍过了,大家可以根据自己的实现来做动态化渲染。

实现预览功能

预览功能这块比较简单, 我们只需要将用户生成的json数据丢进H5渲染器中即可, 这里我们需要做一个渲染页面单独用来预览组件. 先来看看几个预览效果: 基于React+Koa实现一个h5页面可视化编辑器 基于React+Koa实现一个h5页面可视化编辑器 前面的渲染器原理已经介绍了, 这里就不一一介绍了,感兴趣的可以交流讨论.

实现在线下载功能

在线下载这块我们需要用到一个开源库: file-saver, 专门解决前端下载文件困难的窘境. 具体使用举例:

var FileSaver = require('file-saver');
var blob = new Blob(["Hello, world!"], {type: "text/plain;charset=utf-8"});
FileSaver.saveAs(blob, "hello world.txt");

以上代码可以实现将传入的数据下载为txt文件, 如果是Blob, 是不是还能在线下载图片, html呢? 答案是肯定的, 所以我们的下载任务采用该方案来实现.

后端部分实现

后端部分由于涉及的知识点比较多, 不是本文考虑的重点, 所以这里大致提几个点, 大家可以用完全不同的技术来实现后台服务, 比如说PHP, Java, Python或者Egg. 笔者这里采用的是koa. 主要实现功能如下:

  • 保存模板
  • 真机原理的数据源存储
  • 用户相关功能
  • H5图床和静态文件托管

具体代码可以参考笔者的另一篇全栈开发文章

基于nodeJS从0到1实现一个CMS全栈项目

模式基本一致.

github地址:Dooring传送门

后期规划

后期Dooring项目规划如下:

  • 添加模版库模块
  • 添加在线下载网站代码功能
  • 丰富组件库组件,添加可视化组件
  • 添加配置交互功能
  • 组件细分和代码优化
  • 添加typescript支持和单元测试

最新迭代功能

  • 优化H5编辑器界面
  • 添加可视化组件——进度条
  • 修复win下预览样式问题,添加移动端访问出现提示页

最后

如果想学习更多H5游戏, webpacknodegulpcss3javascriptnodeJScanvas数据可视化等前端知识和实战,欢迎在《趣谈前端》一起学习讨论,共同探索前端的边界。

更多推荐

收藏
评论区

相关推荐

教你用200行代码写一个爱豆拼拼乐H5小游戏(附源码)
前言 本文将带大家一步步实现一个H5拼图小游戏,考虑到H5游戏的轻量级和代码体积,我没有使用react或vue这些框架,而采用我自己写的dom库和原生javascript来实现业务功能,具体库代码可见我的文章如何用不到200行代码写一款属于自己的js类库(https://juejin.im/post/6844903880707293198),构建工具我采
H5游戏开发:消灭星星 | Aotu.io「凹凸实验室」
H5游戏开发:消灭星星 by leeenx(https://github.com/leeenx) on 20180
vue h5 对接支付宝,微信支付,微信js支付
vue h5 实现支付(支付宝,微信) h5端实现支付难度不大,只是有些小的点需要注意下,其他的看文档撸就行了。 支付宝很简单,后端返回一个 html ,前端插入调用就行了,微信支付分两种:1、微信内支付(jsapi,微信内浏览器)2、微信外支付(h5支付)。 一、支付宝支付 // 前端啥都不用管,交给后端去干,返回 html 调用点击就好了 /
H5性能优化方面的探索
H5性能优化方面的探索 =========== > H5很重要,很重要,很重要,重要的事情必须重复多遍,H5的优点:跨平台、迭代快、开发体验好。缺点:加载慢,用户体验差。所以在接下来很长一段时间内我将会从H5的几个缺点发面去研究如何优化。 一、缓存问题及其解决办法 ------------ 经常遇到一个问题,H5页面由于缓存问题经常在H5发布新版本之后
HTML5基础知识(一)
Web网页的开发主要包括H5+CSS+JS三个部分,这里先学习一下H5的基础知识。 一、基础语法 ====== 1\. html的基本格式 ------------- <!DOCTYPE html> <html lang="en"> <!--根标签--> <head> <!--头部
HTML5游戏开发凭什么这么火?看了你就知道了...
很多人都会问[H5游戏](https://www.oschina.net/action/GoToLink?url=http%3A%2F%2Fedu.51cto.com%2Fcourse%2Fcourse_id-1307.html)有前途吗?其实我个人是比较看好H5的前景,尤其是在这个移动互联网的时代,Web技术的触角必然会深入到各个领域. 当然H5目前仍然
h5
1.html代码 1 <h3 class="playerTitle">视屏播放器</h3> 2 <div class="player"> 3 <video src="../mp4/chrome.mp4"></video> 4 <div class="controls"> 5
QQ浏览器赵俊:解读腾讯扶持HTM5游戏政策
手机QQ浏览器高级产品经理赵俊作为平台渠道方的代表,受邀出席了“TFC&LAYABOX大型HTML5金秋新品发布会”,并在发布会上分享了腾讯QQ浏览器对于H5游戏的扶持政策以及如何助力H5游戏。 **QQ浏览器在H5产业生态中的定位** 目前手机QQ浏览器是市场占有率和活跃度最高的浏览器,月活跃度2.5亿,腾讯将会逐步开放QQ浏览器的
Android WebView 的三种使用方式
关于原生开发好,还是混合模式开发好,还是 套壳的方式好,在这里不是重点,没有最好的,只有相对适合的。 重点是 那种方式 以最低的资源代价 适合你的业务场景,适合你的团队,根据实际情况来做技术选型。 1,使用h5替代android的view xml 前端将写好的h5 页面放在android 工程的asset目录, 打包的时候会将h5页面一起打在apk里面,
Android与H5混合开发
        Android 和 H5 在移动开发应用中非常广泛。市面上很多App都是使用Android开发的,但使用Android来开发一些比较复杂附属类,提示性的页面是得不偿失的。而H5在制作炫酷动画网页方面比较给力,且具有开发速度快,更新不用依赖于App的更新,只需要服务端更新相应的页面即可,所以App和H5页面相结合就显得尤为重要。而android
Android原生和H5交互;Android和H5混合开发;WebView点击H5界面跳转到Android原生界面。
当时业务的需求是这样的,H5有一个活动商品列表的界面,IOS和Android共用这一个界面,点击商品可以跳转到Android原生的商品详情界面并传递商品ID;  大概就是**点击H5界面跳转到Android原生界面**; 好了,需求已经分析完毕了,Android只需要获取H5的点击事件和传递的参数; 来,上代码: /启用支持javascript
ExMobi+Agile Lite开发内置浏览器APP
微信对内置浏览器的定制封装,使得H5的流量入口再次重新被定义。在原生程序中使用H5也成为非常必要的一种搭配。这也得益于H5对于简单的浏览性质的内容可以很好的进行展现和传播。 由于在实际项目中有需要在移动端使用到H5,而大部分H5页面都是来源于网络的,所以这里尝试使用[ExMobi](https://www.oschina.net/action/GoToLi
LocalDateTime计算时间差
<div class="htmledit\_views" id="content\_views"> <p>LocalDateTime 为java8的新特性之一<br></p> <p><br></p> <p>LocalDateTime.now() 获得当前时间<br></p> <p></p> <h5> </h5><div style="margin-left
Taro Next H5 跨框架组件库实践
![](https://oscimg.oschina.net/oscnet/up-96f83cb51198003133bbb6dfcf26f38b6c9.png) 作者:凹凸曼 - JJ [Taro](https://www.oschina.net/action/GoToLink?url=https%3A%2F%2Fgithub.com%2FNervJS
taro 知识点
* taro 的包: 包名 说明 @tarojs/redux Redux for Taro @tarojs/redux-h5 Forked react-redux for taro @tarojs/plugin-csso Taro压缩CSS文件 ### 内置环境变量 `process.env.TARO_ENV`用于判断当前编译类型,目