一,目标
我们的目标就是尽可能还原老编辑器功能。 大概是这样的:
用户可以选择左侧打印项或基本元素,然后再画布范围内拖动,可以局部设置将设置应用在打印项和元素上,同时可以使用全局设置将设置运用在快递单上。需求大概就是这样,下面看下实现思路。
二,实现思路
我们的思路是当用户action时,我们将action记录下来。最后通过一个方法将记录的数据转化为符合菜鸟打印组件规范的XML。
那么首先来分析下用户的行为(以下简称action)。用户有哪些行为?
1.生成基础元素
2.生成打印项
3.拖动元素
4.更改局部设置
5.更改全局设置。
我们将这些逐个分析开来。
1.生成基本元素。
基本元素的个数是有限的。我们将它们存为枚举值。我们通过一个工厂方法生成基本元素。然后渲染到页面上。
2.生成打印项。
打印项和基本元素区别在于打印项会在打印或者预览的时候使用数据填充。打印项也是有限的,不过打印项相比基本元素要多很多。我们也可以通过工厂生成这些打印项。
3.拖动元素。
这时候改变的仅仅是元素的position。监听元素drag事件即可解决。
4.改变局部设置
这时候改变的仅仅是元素的style,监听局部设置区域组件的oninput或者onchange事件即可。
5.改变全局设置
这时候改变的仅仅是页面的style,监听全局设置区域组件的oninput或者onchange事件即可。
三,整体架构设想
下面就每一个功能块进行讲解。
1.base element 是枚举值。 每一个元素都是一个对象。定义了元素的初始样式。print element 也是枚举值。每一个打印项都是一个对象,同时集成了基本元素,同时多了些属性,如binding source。
2.element factory根据这些对象生成元素(如div)
3.draw panel是核心对象之一。功能一方面将element factory生成元素添加到画板上(add to stage),同时给元素添加key 和 ondragend 事件,并将这些事件通过统一的接口(on position change 和 on style change)暴漏出去供editor监听。同时监听local settint 和 global setting 的 change 事件,将变化应用到元素上,元素变化会同时触发事件同志editor。
4.editor也是核心对象之一。它监听draw panel 暴漏出去的事件,存储在内部。然后当用户保存模板的时候,调用editor的 getTemplate 方法,生成最终的XML模板
5.global setting 改变直接通知 draw panel,然后传到editor 存起来。
6.local setting 改变会通知当前激活的元素(draw panel元素选中的时候对应给元素添加active属性。)
这样设计的好处是扩展容易,耦合性弱。比如要增加一个打印项,只需要在枚举类增加一个对象,并在工厂中注册(以供扫描)。其他组件完全感知不到。
最后总结一下,这里的难点有两个。一个是拖动,另一个是editor的 JSON to XML方法的实现。对于第一个问题,可以工厂生产的每一个元素添加一个drag的注解解决,简单优雅。具体可以看我的另外一个博客 第二个问题,我们刚才说了,editor会将元素信息存起来。 数据结构大概是这样:
{ global: { pageWidth:180, pageHeight:300, xxxxxx } baseRec001: { left: 12, top: 133, width: 10, height: 12, style: { margin: 1, xxxxxx } }, baseText001: { left: 12, top: 133, width: 10, height: 12, style: { margin: 1, xxxxxx } }, printAddr001: { left: 12, top: 133, width: 10, height: 12, style: { margin: 1, xxxxxx } } xxxxxxxxxxxx}
首先推荐看一下菜鸟打印标记语言规范
我们要转化后的结果大概是这样:
]]>
步骤大概是:
1. 根据global 生成page元素。
2. 遍历key 生成其他标签
具体做法就是根据元素top left 。减去画板的top left 算出 top left。然后将样式,宽高写入标签。 注意这里的单位是像素,需要做一下转化。
3. 将上一步生成的标签插入page元素。
editor还有一个对等的方法HTML to JSON。实现思路差不多。具体实现可以参考 https://github.com/ExactTarget/node-xmljson
四,目录结构
根据上面的思路,可以实现真正的组件开发,真正的分工合作,面向接口开发(而不是面向借口)。
├── /assets/ # 资源文件路径│ ├── /build/ # 构建文件输出在这里│ ├── /images/ # 面单图片├── /node_modules/ # 第三方类库和工具├── /src/ # 应用源码│ ├── /components/ # 自定义组件│ ├── globalSetting # 全局设置组件│ ├── localSetting # 局部设置组件│ ├── drawPanel # 画布组件│ ├── elementFactory # 元素工厂│ ├── /entries/ # 应用入口│ ├── /enum/ # 定义各个基本元素和打印元素│ ├── /editor/ # 编辑器核心│ ├── /reducers/ # reducers│ └── /services/ # 处理和服务器的交互├── /test/ # 测试用例├── proxy.config.js # 配置proxy table├── webpack.config.js # webpack 配置└── package.json # 配置入口文件、依赖和 scripts└── deploy.json # 配置项目发布地址,用于自动化发布└── karma.config.js # karma配置文件,用于单元测试└── .eslintrc # eslint 配置文件
注释简单易懂,不多解释了!~
github 地址: https://github.com/azl397985856/template-editor