前言
在去年闲暇时间开发了一个可视化的页面编辑器,这次看到掘金有项目复盘的活动,正好可以拿出来写篇文章,和大家分享下。不知道还能不能赶上活动了~
在开始文章之前你可以先体验下:
在线预览
GitHub 地址
编辑器主要功能
- 元素自由拖拽,放大,缩小,旋转
- 可添加图片,文本,矩形,背景。多种编辑功能(字体,背景,大小,边距等)
- 组件自动吸附,实时参考线(组件可以和画布,自定义参考线以及其他组件进行自动吸附对齐,并显示实时参考线,拖动过程中按下 alt 键可暂时关闭)
- 标尺,参考线,可自定义参考线(在标尺上点击即可生成参开线,可拖动参考线更改位置,双击删除参考线)
- 撤销,重做(支持快捷键,可配置撤销的步数)
- 组件复制,粘贴,锁定,隐藏等
- ctrl + 拖动组件可快速复制组件
- 右键菜单,菜单可配置,可针对组件当前状态灵活生成(即不同的组件可产生不同的菜单)
- 图层面板,可拖拽更改组件图层,可重命名,可在图层面板快速锁定,删除,隐藏组件
- 同时选中多组件(按 ctrl + 左键),可进行多组件对齐
- 数据备份,通过 indexDB 数据库保存在本地(可自动备份,手动备份),并可从备份中恢复数据
- 一键生成 h5 代码
- 编辑画布大小
- 多种快捷键
- 设置中心,可设置撤销功能,备份功能等
- 可通过插件系统二次开发
由于里面的细节比较多,肯定不能将所有点都讲到,我就挑几个主要的写写,有些可能写的比较简略,具体的实现可以看 GitHub 上的源码。
整体架构
这种编辑器一般都是分为 3 个区域,左中右,在左边添加组件,中间操作,右侧可以编辑组件的一些属性,我这个是参考易企秀的设计,中部和右部有一个快捷操作栏,有一些常用的设置。
这些不同的区域对应不同的功能,那么在代码里我们也要将这些不同的功能区域分开:
然后还要有数据,这数据包含了画布属性,组件属性,当前编辑器状态等等,存在 vuex 中:
这里最主要的就是posterItems
属性,是保存当前所有组件的数组。添加组件就是往这个数组中 push 数据,然后遍历posterItems
将组件放在画布上,进而可以编辑这个组件。
组件实现
因为一共有很多种组件,并且这些组件都有一些相同属性,比如位置大小信息,是否锁定,是否隐藏等等,这些相同的属性不可能每个组件都写一遍,所以要就要实现一个基础的组件,这个基础组件包含了所有组件通用的属性,然后其他组件就通过这个组件扩展,我这里通过 class 的方式实现:
defaultWidgetConfig
是组件的配置项,Widget
其实就是初始化这些配置,然后其他组件继承Widget
就可以了,比如我们要实现一个文本组件:
这个构造函数里面就可以初始化一些配置,然后使用时就 new 一个,然后添加到posterItems
中,简化后大概是这样的:
添加完之后,按照上文所说,编辑器中部的操作区域是遍历这个posterItems
的:
这里是通过componentName
来调用不同的组件,刚才的TextWidget
已经配置了componentName
是text-widget
,现在我们就来实现这个组件:
现在添加组件后,你就能在画布上看到demo
了,这只是个示例,更加详细的内容可以看 GitHub 的源码。
注意这里引入了一个 mixin,这个TextWidget.widgetMixin
其实就是Widget
上的:
就是一些组件公共的逻辑,其实这里用高阶组件的方式比较好,用 mixin 的话需要每个组件都要写一遍,比较繁琐,只是当时没想清楚。这个 mixin 一会就会用到,用到再说,这里有个印象即可。
拖拽缩放功能
这个是直接用了一个 Vue 组件:vue-draggable-resizable,直接调用这个组件就行:
这样虽然是可行的,但是有个问题就是我们不仅有文本组件,还有图片,矩形、背景,以后可能还要添加其他组件,而且这个拖动不是套一下就可以的,我们还要写其他的很多逻辑,比如拖动时将 x、y 轴的数据实时更新到组件的属性中,还要有吸附对齐等功能,肯定不能每个组件都去写一遍这些东西,这个时候其实可以把“拖拽”和“组件”拆开,“拖拽”作为一个容器,然后里面嵌套“组件”
这样其实就是多了一层,把拖拽相关的逻辑都写在拖拽容器里,我们只需要实现内层“组件”的逻辑就可以了。
设置组件属性
画布上有了组件后,还要可以在右侧的编辑区域编辑组件,比如字号,背景,边框等等,刚才的TextWidget
里面有一个style
属性,字号什么的就是更改这个属性。
那么我们要做的就是点击这个组件时,将这个组件置为active
状态,然后右侧的区域就显示对应的属性编辑器,不同组件的设置项肯定也不一样,比如TextWidget
需要字号,字体颜色,但是如果我们要做一个矩形的组件,设置项肯定和TextWidget
不同,那么我们就需要单独实现各个组件的属性编辑器,然后判断当前active
状态的组件的类型,根据不同的类型调用不同的属性编辑器。
复制组件
编辑器最必不可少的一个功能就是复制组件,复制组件分为“复制”、“粘贴”两个步骤,复制时就把当前这个组件的配置全部保存下来,,粘贴时就把这个配置拿出来,通过这个配置创建一个组件,添加到posterItems
中去,下面是简化后的代码:
然后粘贴的时候只需要state.posterItems.push(new CopiedWidget(state.copiedWidgets))
,就可以了。
自动吸附
我这里说一下我的实现思路,代码就不贴了,因为比较多,感兴趣的小伙伴可以查看源码。
其实思路很简单,组件在X轴方向上对应“上”“中”“下”三条线,在Y轴上对应“左”“中”“右”三条线:
假设此时有A和B两个组件,现在在拖动B组件,拖动过程中,我们需要实时监测B的左中右三条边和A的是否靠的足够近,就要拿B的左边和A的左中右分别对比,再拿B的中边和A的左中右对比,再拿B的右边和A的左中右对比,总共对比三轮,中间哪一次对比发现两条边的距离达到预设值了,比如说B的左边和A的右边相差了5像素,这时候就可以手动更改B的X轴坐标将B和A对齐:
对应的,上中下三条边也是分别对比,然后匹配到的话就修改B的Y轴坐标。
就是这个思路,实际情况可能比较复杂点,因为不可能只有两个组件,而且除了要组件之间对齐,还要支持自定义参考线,还要和画布的边对齐,感兴趣的同学可以直接看Github的源码。
总结
这篇文章有些地方写的可能比较简略,因为不是一个教程类型的,是对以前的项目做个分享,所以写的比较简略,如果你有什么想法,或者想知道哪个功能点的具体实现细节的,欢迎和我交流。
如果你觉得这个项目还不错的话,欢迎点个赞,感谢~
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!