基于React+Koa实现一个h5编辑器

{"type":"doc","content":[{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"前言"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"前段时间笔者一直忙于"},{"type":"text","marks":[{"type":"strong"}],"text":"数据可视化"},{"type":"text","text":"方面的工作,比如如何实现"},{"type":"text","marks":[{"type":"strong"}],"text":"拖拽式"},{"type":"text","text":"生成可视化大屏,如何定制可视化图表交互和数据导入方案等,这块需求在B端企业中应用非常大,所以非常有探索价值。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"本篇文章并非和数据可视化相关,而是通过抽象技术底层,将其应用于"},{"type":"text","marks":[{"type":"strong"}],"text":"H5页面可视化"},{"type":"text","text":"搭建上,通过技术的手段实现"},{"type":"text","marks":[{"type":"strong"}],"text":"拖拽式生成H5页面"},{"type":"text","text":"。这块也有非常多的应用场景,比如我们需要开发一个移动端网站,一个H5营销页面,H5活动页面等,如果有这样的傻瓜式拖拽的工具生成H5页面,将会极大的提高我们的工作效率。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"接下来笔者将对"},{"type":"text","marks":[{"type":"strong"}],"text":"h5页面可视化编辑器-Dooring"},{"type":"text","text":"做详细的项目分析和原理解读,来带大家深入了解h5可视化搭建页面的原理和技术实现。H5编辑器预览如下:"}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/8b/8b60240cd9270815cf5be3432645e4eb.png","alt":"","title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"github地址:"},{"type":"link","attrs":{"href":"https://github.com/MrXujiang/h5-Dooring","title":null},"content":[{"type":"text","text":"传送门"}]}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"技术栈"}]},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"React"},{"type":"text","text":" 前端主流框架(react,vue,angular)之一,更适合开发灵活度高且复杂的应用"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"dva"},{"type":"text","text":" 主流的react应用状态管理工具,基于redux"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"less"},{"type":"text","text":" css预编译语言,轻松编写结构化分明的css"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"umi"},{"type":"text","text":" 基于react的前端集成解决方案"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"antd"},{"type":"text","text":" 地球人都知道的react组件库"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"axios"},{"type":"text","text":" 强大的前端请求库"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"react-dnd"},{"type":"text","text":" 基于react的拖拽组件解决方案,具有优秀的设计哲学"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"qrcode.react"},{"type":"text","text":" 基于react的二维码生成插件"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"zarm"},{"type":"text","text":" 基于react的移动端ui库,轻松实现美观的H5应用"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"koa"},{"type":"text","text":" 基于nodejs的上一代开发框架,轻松实现基于nodejs的后端开发"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"@koa/router"},{"type":"text","text":" 基于koa2的服务端路由中间件"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"ramda"},{"type":"text","text":" 优秀的函数式js工具库"}]}]}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"需求分析"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在思考需求分析之前我们先来看看"},{"type":"text","marks":[{"type":"strong"}],"text":"Dooring"},{"type":"text","text":"的使用演示:"}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/6d/6deec225d133ee0c23aefa96bc69654e.gif","alt":"","title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"由上面的gif图我们可以分析出,可视化编辑器主要有以下几部分组成:"}]},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"可拖拽的组件库 draggable components"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"盛放组件的画布 canvas"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"组件编辑器 FormEditor"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"头部工具栏 toolBar"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"可拖拽组件我们可以用社区比较火的"},{"type":"text","marks":[{"type":"strong"}],"text":"react-dnd"},{"type":"text","text":","},{"type":"text","marks":[{"type":"strong"}],"text":"react-draggable"},{"type":"text","text":"来实现,由于我们的画布是可拖拽可放大缩小的,所以这里需要对画布赋能,具体实现可参考下文。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"其次就是H5编辑器部分,这部分是核心功能,后面我们会详细分析。还有就是预览,生成预览链接,保存"},{"type":"text","marks":[{"type":"strong"}],"text":"json"},{"type":"text","text":"文件, 保存模版这些功能本质上是对我们"},{"type":"text","marks":[{"type":"strong"}],"text":"json"},{"type":"text","text":"文件的操作,可是目前可视化搭建技术的常用手段之一。先来看看这些功能的演示:"}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/8b/8b60240cd9270815cf5be3432645e4eb.png","alt":"","title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"基础准备"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我们的"},{"type":"text","marks":[{"type":"strong"}],"text":"h5页面可视化编辑器"},{"type":"text","text":"采用"},{"type":"text","marks":[{"type":"strong"}],"text":"umi"},{"type":"text","text":"来作为脚手架工具."}]},{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"umi"},{"type":"text","text":"是可扩展的企业级前端应用框架,以路由为基础的,同时支持配置式路由和约定式路由,保证路由的功能完备,并以此进行功能扩展。然后配以生命周期完善的插件体系,覆盖从源码到构建产物的每个生命周期,支持各种功能扩展和业务需求."}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"这样我们不会关注繁琐的工程配置细节, 可以直接在项目中使用 "},{"type":"text","marks":[{"type":"strong"}],"text":"antd"},{"type":"text","text":" 和 "},{"type":"text","marks":[{"type":"strong"}],"text":"less"},{"type":"text","text":" 这些方案, 并且集成了目前比较流行的"},{"type":"text","marks":[{"type":"strong"}],"text":"css module"},{"type":"text","text":", 可以方便我们在项目里对"},{"type":"text","marks":[{"type":"strong"}],"text":"css"},{"type":"text","text":"进行模块化开发. umi创建项目的具体使用流程如下:"}]},{"type":"codeblock","attrs":{"lang":"javascript"},"content":[{"type":"text","text":"// 创建并进入工程目录\nmkdir dooring && cd dooring\n// 创建umi应用\nyarn create @umijs/umi-app\n// 安装依赖\nyarn // 或者使用npm install\n复制代码"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"简单的三步走策略就能轻松搭建我们的项目工程, 是不是省去了很多麻烦? (在使用这些方式之前我们首先确保自己本地的"},{"type":"text","marks":[{"type":"strong"}],"text":"node"},{"type":"text","text":" 版本是 10.13 或以上)"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在项目搭建完成之后我们调整一下目录结构, 具体如下:"}]},{"type":"codeblock","attrs":{"lang":"javascript"},"content":[{"type":"text","text":"dooring \n├─ src \n│ ├─ assets \n│ │ └─ yay.jpg \n│ ├─ components \n│ ├─ layouts \n│ │ ├─ __tests__ \n│ │ │ └─ index.test.js \n│ │ ├─ index.css \n│ │ └─ index.js \n│ ├─ models \n│ │ └─ editor.js \n│ ├─ pages \n│ │ ├─ __tests__ \n│ │ │ └─ index.test.js \n│ │ ├─ editor \n│ │ │ ├─ components \n│ │ │ │ └─ FormEditor \n│ │ │ │ ├─ index.js \n│ │ │ │ └─ index.less \n│ │ │ ├─ container.js \n│ │ │ ├─ index.js \n│ │ │ └─ index.less \n│ │ ├─ index.css \n│ │ └─ index.js \n│ ├─ service \n│ │ └─ editor.js \n│ ├─ app.js \n│ └─ global.css \n├─ package.json \n└─ webpack.config.js \n复制代码"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"page目录下的editor使我们的主页面, components存放我们的公共组件, models和service主要负责处理dva的状态管理逻辑, 其他部分大家可以更具需求自由定义.此处仅供学习参考."}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在项目创建完之后我们还需要安装可视化方面必备的第三方组件, 笔者调研社区精选组件之后采用了一下方案:"}]},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"react-dnd"},{"type":"text","text":" react拖拽组件"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"react-color"},{"type":"text","text":" react颜色选择组件,用于H5编辑器的编辑颜色部分"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"react-draggable"},{"type":"text","text":" 用于组件或者画布的拖拽移动"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"react.qrcode"},{"type":"text","text":" 基于react的二维码生成组件, 能以react组件的方式生成二维码"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"以上组件在运行项目前大家可以自行安装."}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"正文"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在最好项目开发准备之后,我们就来开始设计我们的h5页面可视化编辑器-"},{"type":"text","marks":[{"type":"strong"}],"text":"Dooring"},{"type":"text","text":"."}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"H5编辑器实现"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"H5可视化编辑器主要需要4个部分,在文章开头也分析过, 这里用图来巩固一下:"}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/10/102897a349673d59f93bdca818aa0a33.png","alt":"","title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"以上是最基本也是最核心的功能展示模型,接下来我们会一一将其拆解并逐个实现."}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"实现原理"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我们都知道, 目前比较流行的页面可视化搭建方案可以有如下几种:"}]},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在线编辑代码实现"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在线编辑json实现"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"无代码化拖拽实现(底层基于json配置文件)"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"笔者做了一下优缺点对比图,如下:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"方案定制化程度缺点在线编辑代码最高使用成本高,对非技术人员不友好,效率低在线编辑json较高需要熟悉json,有一定使用成本, 对非技术人员不友好,效率一般无代码化拖拽实现高使用成本低, 操作基本无门槛,效率较高"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"由以上分析来看, 为了开发一个低门槛, 对任何人适用的可视化编辑器, 笔者将采用第三种方案来实现, 目前市面上已有的产品也有很多, 比如说易企秀, 兔展, 百度H5等等. "},{"type":"text","marks":[{"type":"strong"}],"text":"实现原理其实还是基于json, 我们通过可视化的手段将自己配置的 页面转化为json数据,最后在基于json渲染器来动态生成H5站点"},{"type":"text","text":"."}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/16/16ec7292e9c4812d75f27cef78210497.png","alt":"","title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"数据结构设计"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"为了提供组件的自定义能力,我们需要定义一套高可用的数据结构, 这样才能实现因组件需求变更而带来的维护性优势."}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在开始设计数据结构之前我们先来拆解一下模块:"}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/b5/b506c9d39764b053275b5f886134c0de.png","alt":"","title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"不同的组件都对应不同的\"编辑区域\".我们需要设计一套统一的标准的配置来约定它, 这样对于表单编辑器的设计也非常有利, 具体拆解如下:"}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/87/872b5839a3db1096374b6ae2fe2a4e45.png","alt":"","title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"经过以上分析之后, 笔者设计了类似下面的数据结构:"}]},{"type":"codeblock","attrs":{"lang":"javascript"},"content":[{"type":"text","text":"\"Text\": {\n \"editData\": [\n {\n \"key\": \"text\",\n \"name\": \"文字\",\n \"type\": \"Text\"\n },\n {\n \"key\": \"color\",\n \"name\": \"标题颜色\",\n \"type\": \"Color\"\n },\n {\n \"key\": \"fontSize\",\n \"name\": \"字体大小\",\n \"type\": \"Number\"\n },\n {\n \"key\": \"align\",\n \"name\": \"对齐方式\",\n \"type\": \"Select\",\n \"range\": [\n {\n \"key\": \"left\",\n \"text\": \"左对齐\"\n },\n {\n \"key\": \"center\",\n \"text\": \"居中对齐\"\n },\n {\n \"key\": \"right\",\n \"text\": \"右对齐\"\n }\n ]\n },\n {\n \"key\": \"lineHeight\",\n \"name\": \"行高\",\n \"type\": \"Number\"\n }\n ],\n \"config\": {\n \"text\": \"我是文本\",\n \"color\": \"rgba(60,60,60,1)\",\n \"fontSize\": 18,\n \"align\": \"center\",\n \"lineHeight\": 2\n }\n}\n复制代码"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"通过这种标准化结构设计之后,我们可以很方便的实现我们所需要的编辑页面的功能, 并且后期扩展非常方便, 只需要往editData添加配置即可. 至于动态表单编辑器的实现,方案有很多, 笔者之前也写过相关的文章, 这里就不详细介绍了."}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"基于react搭建一个通用的表单管理配置平台(vue同)"}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"组件库设计"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"组件库设计考虑的一个重要的问题就是体积和渲染问题, 一旦组件库变的越来越多, 那意味着页面加载会非常慢,所以我们需要实现异步加载组件和代码分割的能力, umi提供了这样的功能,我们可以基于它提供的api去实现自己的额按需组件."}]},{"type":"codeblock","attrs":{"lang":"javascript"},"content":[{"type":"text","text":"import { dynamic } from 'umi';\n\nexport default dynamic({\n loader: async function() {\n // 这里的注释 webpackChunkName 可以指导 webpack 将该组件 HugeA 以这个名字单独拆出去\n const { default: HugeA } = await import(/* webpackChunkName: \"external_A\" */ './HugeA');\n return HugeA;\n },\n});\n复制代码"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"通过以上的方式来定义包裹我们的每一个组件, 这样就能实现按需加载了, 但是最好的建议是不需要每个组件都按需加载和拆包,对于"},{"type":"text","marks":[{"type":"strong"}],"text":"标题"},{"type":"text","text":", "},{"type":"text","marks":[{"type":"strong"}],"text":"通知栏"},{"type":"text","text":","},{"type":"text","marks":[{"type":"strong"}],"text":"页头"},{"type":"text","text":","},{"type":"text","marks":[{"type":"strong"}],"text":"页脚"},{"type":"text","text":"这些组件, 我们完全可以把它放在一个组里,这样不但对不会影响加载速度, 还能减少一定的http请求."}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"笔者这里简单举一个组件实现的例子,方便大家理解:"}]},{"type":"codeblock","attrs":{"lang":"javascript"},"content":[{"type":"text","text":"const Header = memo((props) => {\n const { \n bgColor,\n logo,\n logoText,\n fontSize,\n color\n } = props\n return
\n
\n {logoText}\n
\n
{ logoText }
\n
\n})\n复制代码"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"上面的Header组件的props属性完全是由我们之前设计的json结构来定义的,在用户编辑的过程中将收据收集并传给Header组件。最后一步是将这些组件动态传给"},{"type":"text","marks":[{"type":"strong"}],"text":"dynamic"},{"type":"text","text":"组件, 这块在上文也介绍过了,大家可以根据自己的实现来做动态化渲染。"}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"实现预览功能"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"预览功能这块比较简单, 我们只需要将用户生成的json数据丢进H5渲染器中即可, 这里我们需要做一个渲染页面单独用来预览组件. 先来看看几个预览效果:"}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/cc/cc2a3120fa3e9f91b8e4232ddba0b634.png","alt":null,"title":"","style":[{"key":"width","value":"50%"},{"key":"bordertype","value":"none"}],"href":"","fromPaste":false,"pastePass":false}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/56/56dcc4129cf232980c2828be4ac04fbe.png","alt":null,"title":"","style":[{"key":"width","value":"50%"},{"key":"bordertype","value":"none"}],"href":"","fromPaste":false,"pastePass":false}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"前面的渲染器原理已经介绍了, 这里就不一一介绍了,感兴趣的可以交流讨论."}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"实现在线下载功能"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在线下载这块我们需要用到一个开源库: "},{"type":"text","marks":[{"type":"strong"}],"text":"file-saver"},{"type":"text","text":", 专门解决前端下载文件困难的窘境. 具体使用举例:"}]},{"type":"codeblock","attrs":{"lang":"javascript"},"content":[{"type":"text","text":"var FileSaver = require('file-saver');\nvar blob = new Blob([\"Hello, world!\"], {type: \"text/plain;charset=utf-8\"});\nFileSaver.saveAs(blob, \"hello world.txt\");\n复制代码"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"以上代码可以实现将传入的数据下载为txt文件, 如果是Blob, 是不是还能在线下载图片, html呢? 答案是肯定的, 所以我们的下载任务采用该方案来实现."}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"后端部分实现"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"后端部分由于涉及的知识点比较多, 不是本文考虑的重点, 所以这里大致提几个点, 大家可以用完全不同的技术来实现后台服务, 比如说"},{"type":"text","marks":[{"type":"strong"}],"text":"PHP"},{"type":"text","text":", "},{"type":"text","marks":[{"type":"strong"}],"text":"Java"},{"type":"text","text":", "},{"type":"text","marks":[{"type":"strong"}],"text":"Python"},{"type":"text","text":"或者"},{"type":"text","marks":[{"type":"strong"}],"text":"Egg"},{"type":"text","text":". 笔者这里采用的是"},{"type":"text","marks":[{"type":"strong"}],"text":"koa"},{"type":"text","text":". 主要实现功能如下:"}]},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"保存模板"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"真机原理的数据源存储"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"用户相关功能"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"H5图床和静态文件托管"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"具体代码可以参考笔者的另一篇全栈开发文章"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"基于nodeJS从0到1实现一个CMS全栈项目"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"模式基本一致."}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"github地址:"},{"type":"link","attrs":{"href":"https://github.com/MrXujiang/h5-Dooring","title":null},"content":[{"type":"text","text":"Dooring传送门"}]}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"后期规划"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"后期"},{"type":"text","marks":[{"type":"strong"}],"text":"Dooring"},{"type":"text","text":"项目规划如下:"}]},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"丰富组件库组件,添加可视化组件"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"添加配置交互功能"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"组件细分和代码优化"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"添加PC端搭建平台"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"添加表单设计平台"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"添加typescript支持和单元测试"}]}]}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"最新迭代功能"}]},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"优化H5编辑器界面"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"添加可视化组件——进度条"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"修复win下预览样式问题,添加移动端访问出现提示页"}]}]}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"最后"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"如果想学习更多"},{"type":"text","marks":[{"type":"strong"}],"text":"H5游戏"},{"type":"text","text":", "},{"type":"text","marks":[{"type":"strong"}],"text":"webpack"},{"type":"text","text":","},{"type":"text","marks":[{"type":"strong"}],"text":"node"},{"type":"text","text":","},{"type":"text","marks":[{"type":"strong"}],"text":"gulp"},{"type":"text","text":","},{"type":"text","marks":[{"type":"strong"}],"text":"css3"},{"type":"text","text":","},{"type":"text","marks":[{"type":"strong"}],"text":"javascript"},{"type":"text","text":","},{"type":"text","marks":[{"type":"strong"}],"text":"nodeJS"},{"type":"text","text":","},{"type":"text","marks":[{"type":"strong"}],"text":"canvas数据可视化"},{"type":"text","text":"等前端知识和实战,欢迎在《趣谈前端》一起学习讨论,共同探索前端的边界。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}}]}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章