Open vivipure opened 2 years ago
日常的工作有很大一部分都是编辑器的开发。由于业务需求,今年推动了全景编辑器2.0的重构。本文会主要讲述此次重构的全部细节。
作为一款编辑器,老版全景编辑器的功能存在很多问题。
当前的业务架构不在满足后续业务的开发,于是我决定重构。
作为编辑器的主程,产品在规划2.0版的新功能时,我基于当前业务现状和主管提出了重构的想法。通过重构后,主要能够实现的目标有:
首先是数据,和H5编辑器不同,老版本的全景编辑器在前端存储的数据是很零散的。完全通过 krapno 读取全景的数据。在数据更改时直接提交后端,更改配置 XML 文件,前后端耦合非常严重。
krapno
XML
因此数据方面我完全放弃从 krpano 实例中读取数据,而是在进入编辑器时获取该物料的 XML配置文件,然后将 XML 转化为 DOM,从 DOM 中获取数据构建整个全景的 JSON 树,后续的编辑器操作都基于 JSON 操作。
krpano
DOM
JSON
从 XML 到 JSON 的转化过程中,我对全景中所有的组件都进行数据建模。包括 热点,图层,标尺等,声明的类大约 20余种。每个类都提供解析 XML 获取 JSON 的方法,最终对整个 XML 进行操作,就获取到所有的组件数据了。
class Hotspot { static parseDOM(DOM) { ... return {...} } }
对数据建模的好处, 不止在于解析数据。上面我也提到,我希望将全景编辑的逻辑和UI逻辑抽离,而通过类来对相关的组件进行数据和逻辑的封装就非常好用。我将 krpano 相关的操作全部封装到对应的类中,操作数据时,直接调用相关的类和实例的方法即可
class Hotspot { add() {} remvoe() {} update(...) {} }
这样就不用在 Vue 代码中写 krpano 的相关逻辑了,界面表单在更新 JSON 数据时,使用封装好的类同步预览的视图即可。
Vue
旧代码中包含很多的大组件,例如热点组件,热点的类型有7种,每种热点的属性各有异同。老组件中直接包含所有热点的配置,各种状态判断,十分混乱。
这里的重构逻辑很简单,拆分组件,每种类型热点对应相关的属性组件,编辑时通过数据类型标识识别对应组件然后用动态组件进行展示。
对于其他的大组件,我们也采用一样的方法进行抽离,保证组件的颗粒度,保证组件的业务复杂度不能过高。
用户上传的全景图是一张2:1的图片,无法直接被全景使用。我们使用 krpano 官方提供的切图工具在服务器进行切图,然后放到对应的物料文件夹中。
重构时有考虑前端切图,普通切图将全景图分割为6张图片是可以实现的,但是业务场景更多的需要的是高清切图,由于算法问题,最终还是放弃了这个小优化。
老版本切图存在一个问题,就是用户在进行切图时,对服务器的压力特别大,后端在队列管理上也处理的不好,没有进行异步处理。这就导致多用户多图上传时,等待的时间可能会特别久,如果接口超时失败,前端也未进行相关处理。10张切图,有一张失败了都会造成整体操作失败,用户体验十分糟糕。
我这边的处理也很简单,切图时不使用遮罩阻止用户操作。将每个切图都变成任务,每个任务有各自的进度条,任务之间互不影响。这样用户在编辑物料时也能进行上传的操作,用户使用体验大幅提高。
同时为了缓解服务器压力,前端封装了一个 任务调度器 scheduler, 用户任务最多并行两个。 当然这个处理的收益还是比较小的,也不能真正解决问题,还是需要后端进行优化。
scheduler
重构一开始的目的就是为了最终保存,用户拥有数据保存的决定权。在编辑器对 JSON进行编辑后,我们需要进行转换。将 JSON 重新转化为 XML,这里同样使用类的序列化方法
class Hotspot { serialize(data) { ... return `<hotspot ... />` } }
这里在进行开发时还是遇到了坑, 一开始我们使用的是对属性进行遍历,然后通过字符串组装成 XML,由于业务场景不需要关心 XSS 的问题。但是在代码提测之后,问题接踵而来。当输入特殊字符或者引号之类的特殊符号时,由于 XML 的格式要求,XML 就变成了非法的 XML 文档了,这也造成了全景保存失败。
XSS
因此我们选择通过将 JSON 转化成通过 DOM 提供的能力来进行序列化
const hotspot = document.createElement('hotspot') ... hotspot.setAttribute(key, value) ... return hotspot.outerHTML
这种方法解决了大部分的问题,但是还是会有不少的坑,例如 word 中的特殊空格,就是无法进行保存。定位到问题后,只能根据 unicode 进行匹配替换。
word
unicode
还有富文本的情况,富文本通过属性进行保存时也会存在问题,要么是预览异常,要么是回显到富文本编辑器异常。最终还是决定针对富文本进行字符串拼接,然后将&,<,>,"符号进行实体化处理,上线后到目前为止暂时无任何异常。
&
<
>
"
经过2.0 的重构,在业务架构上减少了后端的依赖,大幅提高了用户的使用体验。 让用户可以通过全景编辑器快速制作出全景漫游物料,添加丰富的交互效果。
在前端代码设计上,让全景编辑的逻辑完全独立,针对全景模块进行数据建模,对后续维护和新增功能十分的友好。
当然通过这次大的重构,无论是业务架构设计还是组件拆分,我都有了巨大的收获。
当然重构到目前为止,编辑器已经重构的十分强大了。但是还是缺少一个最重要的功能: 历史记录。后面我会有专文介绍历史记录功能的实现,和具体业务难点。
这个重构的2.0编辑器能看看嘛
这个是公司的内部项目,不对外开发。编辑器的核心逻辑无非是数据驱动,UI层通过交互改动一份JSON数据,最终JSON数据转化为真正所需要结构。和大部分的H5编辑器没有特别大的区别
一. 业务背景
日常的工作有很大一部分都是编辑器的开发。由于业务需求,今年推动了全景编辑器2.0的重构。本文会主要讲述此次重构的全部细节。
作为一款编辑器,老版全景编辑器的功能存在很多问题。
当前的业务架构不在满足后续业务的开发,于是我决定重构。
二. 重构目标
作为编辑器的主程,产品在规划2.0版的新功能时,我基于当前业务现状和主管提出了重构的想法。通过重构后,主要能够实现的目标有:
三. 具体实操
3.1 数据建模
首先是数据,和H5编辑器不同,老版本的全景编辑器在前端存储的数据是很零散的。完全通过
krapno
读取全景的数据。在数据更改时直接提交后端,更改配置XML
文件,前后端耦合非常严重。因此数据方面我完全放弃从
krpano
实例中读取数据,而是在进入编辑器时获取该物料的 XML配置文件,然后将XML
转化为DOM
,从DOM
中获取数据构建整个全景的JSON
树,后续的编辑器操作都基于JSON
操作。从
XML
到JSON
的转化过程中,我对全景中所有的组件都进行数据建模。包括 热点,图层,标尺等,声明的类大约 20余种。每个类都提供解析XML
获取JSON
的方法,最终对整个XML
进行操作,就获取到所有的组件数据了。对数据建模的好处, 不止在于解析数据。上面我也提到,我希望将全景编辑的逻辑和UI逻辑抽离,而通过类来对相关的组件进行数据和逻辑的封装就非常好用。我将
krpano
相关的操作全部封装到对应的类中,操作数据时,直接调用相关的类和实例的方法即可这样就不用在
Vue
代码中写krpano
的相关逻辑了,界面表单在更新JSON
数据时,使用封装好的类同步预览的视图即可。3.2 组件拆分
旧代码中包含很多的大组件,例如热点组件,热点的类型有7种,每种热点的属性各有异同。老组件中直接包含所有热点的配置,各种状态判断,十分混乱。
这里的重构逻辑很简单,拆分组件,每种类型热点对应相关的属性组件,编辑时通过数据类型标识识别对应组件然后用动态组件进行展示。
对于其他的大组件,我们也采用一样的方法进行抽离,保证组件的颗粒度,保证组件的业务复杂度不能过高。
3.3 切图处理
用户上传的全景图是一张2:1的图片,无法直接被全景使用。我们使用
krpano
官方提供的切图工具在服务器进行切图,然后放到对应的物料文件夹中。重构时有考虑前端切图,普通切图将全景图分割为6张图片是可以实现的,但是业务场景更多的需要的是高清切图,由于算法问题,最终还是放弃了这个小优化。
老版本切图存在一个问题,就是用户在进行切图时,对服务器的压力特别大,后端在队列管理上也处理的不好,没有进行异步处理。这就导致多用户多图上传时,等待的时间可能会特别久,如果接口超时失败,前端也未进行相关处理。10张切图,有一张失败了都会造成整体操作失败,用户体验十分糟糕。
我这边的处理也很简单,切图时不使用遮罩阻止用户操作。将每个切图都变成任务,每个任务有各自的进度条,任务之间互不影响。这样用户在编辑物料时也能进行上传的操作,用户使用体验大幅提高。
同时为了缓解服务器压力,前端封装了一个 任务调度器
scheduler
, 用户任务最多并行两个。 当然这个处理的收益还是比较小的,也不能真正解决问题,还是需要后端进行优化。3.4 最终保存
重构一开始的目的就是为了最终保存,用户拥有数据保存的决定权。在编辑器对
JSON
进行编辑后,我们需要进行转换。将JSON
重新转化为XML
,这里同样使用类的序列化方法这里在进行开发时还是遇到了坑, 一开始我们使用的是对属性进行遍历,然后通过字符串组装成
XML
,由于业务场景不需要关心XSS
的问题。但是在代码提测之后,问题接踵而来。当输入特殊字符或者引号之类的特殊符号时,由于XML
的格式要求,XML
就变成了非法的XML
文档了,这也造成了全景保存失败。因此我们选择通过将
JSON
转化成通过DOM
提供的能力来进行序列化这种方法解决了大部分的问题,但是还是会有不少的坑,例如
word
中的特殊空格,就是无法进行保存。定位到问题后,只能根据unicode
进行匹配替换。还有富文本的情况,富文本通过属性进行保存时也会存在问题,要么是预览异常,要么是回显到富文本编辑器异常。最终还是决定针对富文本进行字符串拼接,然后将
&
,<
,>
,"
符号进行实体化处理,上线后到目前为止暂时无任何异常。四.最后结果
经过2.0 的重构,在业务架构上减少了后端的依赖,大幅提高了用户的使用体验。 让用户可以通过全景编辑器快速制作出全景漫游物料,添加丰富的交互效果。
在前端代码设计上,让全景编辑的逻辑完全独立,针对全景模块进行数据建模,对后续维护和新增功能十分的友好。
当然通过这次大的重构,无论是业务架构设计还是组件拆分,我都有了巨大的收获。
当然重构到目前为止,编辑器已经重构的十分强大了。但是还是缺少一个最重要的功能: 历史记录。后面我会有专文介绍历史记录功能的实现,和具体业务难点。