仿“易企秀”编辑器之拖拉拽

概述

最近心血来潮,想仿造一下易企秀,作一个新的编辑器。主要是3年前那个编辑器有些自动化方面和动画性能方面的缺陷吧,人生不能有遗憾就早早动手吧。选择易企秀,而不是互动大师,主要是由于易企秀的技术难度比较低,编辑器的核心部分,若是全职开发,估计一个月就作完了。若是是互动大师,业余时间开发根本估计核心部分都够呛。核心部分包括拖拉拽,组件生命周期,场景增删改,工程增删改,完善的组件事件通讯机制,撤销恢复还有动画编辑。前端

有兴趣的朋友能够进 github 看看。里面有在线演示的地址。该项目还在持续开发中,轻拍,别打脸。git

 

拖拉拽的核心原理

不一样的编辑器,无论怎么样,拖拉拽的业务逻辑必定要本身写,这是血的教训。两年前,接手一家公司的编辑器,那个编辑器的核心部分是用某个开源项目的,性能有问题,核心元数据的数据结构也有问题。重构了几回,才契合当时公司的业务。github

转回正题。拖拉拽,说白了,就是三个事件组成,mousedown,mousemove,mouseup。设计模式

mousedown的时候,记录点击的元素,空白处?某个元素的旋转点,缩放点仍是移动的区域?假设用户点击了旋转点,那么记录下要旋转的元素,元素的中心点,而后mousemove的时候根据中心点和当前鼠标的位置,计算出角度,而后渲染新的角度到界面上。以此类推,移动和缩放也是差很少的,只是细节逻辑不同。浏览器

mousemove的时候,主要是为了实时渲染拖拉拽的结果,包括移动的时候要吸附参考线。性能优化

mouseup的时候,清除mousedown的时候记录的一些变量。数据结构

性能优化

 

拖拉拽,其实难的是性能处理,尤为是移动端。要是一个场景里面几百个组件,移动端就很痛苦了。编辑器

首先必须使用事件委托,由于事件具备冒泡机制,所以咱们能够利用冒泡的原理,把事件加到父级上,触发执行效果。这样作的好处固然就是提升性能了。函数

假如没有使用事件委托,那么100个组件,每一个组件1个旋转点,8个缩放点,1个移动点,那么就要添加800个mousedown事件。若是使用事件委托,就只要一个mousedown事件就好。性能

原理是用户点击页面的时候,事件里有个target属性,也就是用户所点击的元素,经过元素的class判断是否是触发点(触发点就是移动点,旋转点,缩放点的统称),若是不是,就找元素的父节点,继续判断是否是触发点,以此类推。一直找到document,若是没找到触发点,那么就是点击了空白处,找到触发点好办了,就找触发点所属的组件。有触发点的类型和所按下的组件,mousemove的时候就能够根据分支进行不一样的处理。

晚点我在补张示意图。

 

弄完事件委托,就弄函数节流了。主要是mousemove是高频率的事件,频率不要那么高就行了。

伪代码以下

private _debounce:Debounce = new Debounce(50,true);

。。。

this._mouseMoveRecycle = Renderer.addEventListener(document, "mousemove", (event: MouseEvent) => {
        if (!isMouseDown) {
          return;
        }
        this._debounce.handle(()=>{
            //处理mousemove的内容了
        });
});        

 

 

兼容移动端

搞完功能就是兼容性了,大前端最蛋疼的就是这个了。

要兼容移动端,那么就是touchstart,touchmove,touchend三个事件了,这个网上大把教程,就不细说了。有一点要当心的,就是touchend返回的event里面,有些浏览器是没有event.pageX的,若是要用到,那么就在touchmove实时记录,touchend的时候拿来用就行了。

 

假若有一天你的领导说,手机移动端是能旋转的,旋转了以后,编辑器的组件的位置就错乱,由于组件的位置是使用absolute没有自适应。

示意图以下(红色框表示手机屏幕):

既然看不到,咱们就把编辑器根据orientation进行旋转。变成下面的样子,用户不就能够继续编辑了。

666,问题来了,并且是很大的问题。旋转以后,整个世界的坐标系都换了。

其实只要把event.pageX和event.pageY根据window.orientation进行转换就好。这部分当我作到移动端的时候,会补上去。

到这里就差很少了。差很少?由于有些手机浏览器不支持window.orientation,因此还差一步兼容处理。没事,其实移动端屏幕旋转的时候,会触发resize事件,而后根据屏幕的宽高计算orientation。或者mousedown的时候,根据屏幕的宽高进行获取。

下面是伪代码:

//判断浏览器支持window.orientation否,不支持就经过事件去获取
window.onresize = function(){
window.orientation=(window.innerWidth > window.innerHeight)? "landscape":"portrait";  
}

 

github地址:https://github.com/qq386232894/h5-editor 

 

大功告成,有什么遗漏的,但愿搞过这方面的大牛一块儿来探讨。

 

下一篇文章,写下这个编辑器用到的设计模式吧。

相关文章
相关标签/搜索