實現效果:
6-01完美拖動css
這裏沒有使用h5的拖動,畢竟原題也是考察藉助鼠標事件實現自定義的拖動,因此就借鑑了《js高級程序設計》裏的自定義拖動本身封裝了個拖動api,固然因爲作這個系列題目使用的都是es5的語法,因此IE8往下就兼容不到了(有興趣的能夠本身一試)。web
首先有一個自定義的事件對象構造函數EventTarget
,內部封裝了事件的監聽、觸發、移除監聽三個基本操做。再由EventTarget
拓展一個和拖動操做有關的單例對象,這個對象是的主要任務就是把指定元素上的觸發的鼠標事件轉換爲觸發咱們自定義的拖動事件,該對象接口方法介紹以下:api
enable()
:開啓整個文檔上拖動事件與鼠標事件的關聯瀏覽器
disable()
:關閉拖動事件與鼠標事件的關聯,也就是點擊時再也不觸發自定義的拖動操做緩存
addHandler(eventName, handler)
:給相應拖動事件添加處理函數。注意因爲拖動事件是全局關聯,因此若處理函數是針對指定元素的操做,不只要先在該元素上添加class="draggable"
,並且在處理函數裏還要判斷觸發事件的就是該元素才行函數
removeHandler(eventName, handler)
:移除指定的拖動事件上的某個處理函數動畫
再介紹下三個自定義的拖動事件:es5
dragstart
:由mousedown
轉換而來,事件對象的屬性有:spa
type: 'dragstart'設計
target: 鼠標點擊的draggable元素
clientX, clientY: 同mousedown
drag
:由mousemove
轉換而來,事件對象的屬性有:
type: 'drag'
target: 鼠標點擊的draggable元素
clientX, clientY: 同mousemove
diffX, diffY: 用於校訂clientX
, clientY
與實際要達到的拖動位置的誤差。需在dragstart
作指定,不然默認值爲0
dragend
:由mouseup
轉換而來,事件對象的屬性有:
type: 'dragend'
target: 鼠標點擊的draggable元素
clientX, clientY: 同mouseup
api有了,咱們就能夠調用enable
開啓拖動,再和原生的事件同樣給題目中的拖動塊添加三個事件處理函數便可。只是要注意因爲addHandler
方法不能指定元素,因此還得在拖動塊上添加class="draggable"
、並在處理函數裏作個判斷才行。利器在手,接下來要作的限制移動範圍、展現座標、回放拖動等都是小case啦,這題的代碼就當是這套api的示例了。
實現效果:
6-02仿騰訊微博效果
此次來個大製做,只要再搭個後臺弄點數據交互,幾乎就是一個完整的webApp了。就頁面而言,主要就是實現表單獲取數據和數據列表的展示,因此這裏分別封裝了兩個單例MsgForm
和MsgList
對應表單和展現列表,來實現相關的功能。
MsgForm
只提供了init
方法來添加各個表單組件的事件監聽。該部件最重要的就是對錶單的驗證了,既要有提交時的驗證,也要保證能在輸入時即時給出字數提醒。正則用的溜的話其實也不難。
至於MsgList
則主要實現增刪DOM的操做,難點就是呈現和隱藏兩個動畫的實現。這裏利用setTimeout
手動調節出了效果,寫得仍是比較ugly的,拓展性還不強。
最後注意幾個語法上的問題,一是鍵盤事件也是可使用輔助按鍵屬性:ctrlKey
, altKey
, shiftKey
, metaKey
,而不用像第五課作過的一題那樣去緩存按鍵了。第二就是用js獲取的css屬性值,不管是經過element.style
仍是window.getComputedStyle()
,返回的都是字符串,因此要進行運算只能手動轉爲數字;這一點和js中獲取寬高、位置的屬性如offsetWidth
等直接返回數字不一樣。
實現效果:
6-03自定義多級右鍵菜單
第五課第六題中已經經過contextmenu
事件實現了一級右鍵菜單,因此這題只要在上面再添加事件喚出子菜單便可。
首先解決第五課第六題題在實現時留下的一個bug:菜單有時會顯示到容器外。緣由很簡單,因爲是先定位菜單再顯示菜單,致使要依靠寬高的定位並不能起做用;因此這裏保證菜單先顯現出來擁有寬高便可。
而後就是實現多級子菜單了,這裏直接使用css的hover
僞類控制顯隱,只把定位交給mouseover
事件來作便可。由於若是使用mouseover
和mouseout
控制顯隱,因爲冒泡的特性會致使移到子菜單前父菜單就已經消失的問題,雖然前面作過的題目有用過setTimeout
延遲消失來解決這一問題的,但這樣寫起來實在太醜陋了,不考慮兼容老舊瀏覽器狀況下仍是用css作更清晰高效。
至於如何定位,也是沿用第五課的思路:設置各級子菜單絕對定位;顯示菜單時先計算容器右側和底部的剩餘空間;再分別判斷可否容得下子菜單的寬高,若容得下則子菜單出如今父元素右下角,不然就作出相應的變化。
最後再總結遇到的幾個問題:
子菜單定位時遇到的問題:js的offsetTop
, offsetLeft
屬性得到的都是相對父容器的位置而不是絕對位置,要獲取絕對位置必須進行向上遍歷。
子菜單li
元素的寬度不能容得下其文本內容,致使文本摺疊:不設置寬度的絕對定位元素,其寬度是由最長的文本內容決定的。若文本自動換行那最長文本就是最長單詞而已,因此得設置white-space: nowrap;
使文本不換行,才能保證li
元素的寬度可以容得下其全部文本內容。而具體關於元素寬高爲auto
時其寬高在不一樣狀況會受到什麼影響,我會專門寫一篇文章來分析分析~
---第六課完---