仿「易企秀」編輯器之拖拉拽

概述

最近心血來潮,想仿造一下易企秀,作一個新的編輯器。主要是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 

 

大功告成,有什麼遺漏的,但願搞過這方面的大牛一塊兒來探討。

 

下一篇文章,寫下這個編輯器用到的設計模式吧。

相關文章
相關標籤/搜索