再次談論React.js實現原生js拖拽效果引起的一系列問題_javascript技巧

來源:互聯網
上載者:User

React 起源於 Facebook 的內部項目,因為該公司對市場上所有 JavaScript MVC 架構,都不滿意,就決定自己寫一套,用來架設 Instagram 的網站。做出來以後,發現這套東西很好用,就在2013年5月開源了。由於 React 的設計思想極其獨特,屬於革命性創新,效能出眾,代碼邏輯卻非常簡單。所以,越來越多的人開始關注和使用,認為它可能是將來 Web 開發的主流工具。

前幾天寫的那個拖拽,自己留下的疑問。。。這次在熱心博友的提示下又修正了一些小小的bug,也加了拖拽的邊緣檢測部分。。。就再聊聊拖拽吧

一、不要直接操作dom元素

react中使用了虛擬dom的概念,目地就是要盡量避免直接操作dom元素,所以我們在對dom元素進行操作的時候需要注意,我之前為了擷取form的參數就直接用了var dragBox=document.getElementById('form')去找dom,但是其實記錄from的初始位置,可以在其子組件更新父組件參數的時候調用。即在MyFrom組件中擷取,如下代碼:

onChildChanged:function(newState){/*以下為修改處*/var computedStyle=document.defaultView.getComputedStyle(ReactDOM.findDOMNode(this.refs.dragBox),null);newState.left=computedStyle.left;newState.top=computedStyle.top;/*以上為修改處*/this.setState(newState);},

這樣就可以直接在父組件中操作自己,而不是在子組件中調用。

二、onmousemove和onmouseup事件應該綁定到document上

拖拽事件中,當滑鼠在DragArea中按下後,就應該檢測滑鼠在document中移動的距離及何時彈起。否則直接綁定在form的話會有一個不雅的地方,就是拖動條拖動邊緣附近的時候,如果滑鼠速度快一點會失效,滑鼠再回來拖動條會自動吸上滑鼠。因此利用react初始化階段的componentDidMount函數,這個函數是組件被裝載後才會被調用,也就是說調用這個方法的時候,組件已經被渲染到了頁面上,這個時候可以修改DOM。也就是說此時把相應事件再綁定到document上面,如下代碼:

componentDidMount:function(){document.addEventListener('mousemove',(e)=>{this.move(e);},false);/*ES6新特性,箭頭函數,需要依賴jsx編譯工具才能正確運行*/document.addEventListener('mouseup',(e)=>{this.endDrag(e);},false);},

這樣就可以消除那個小小的bug啦!

三、增加邊緣檢測

一般情況下的拖拽,我們都是不希望能夠拖出可視視窗之外的,因此這就需要檢測。檢測四個方向上的位置,即上、下、左、右。顯然,上的距離top和左邊left的距離必須要大於等於0,下邊和右的距離必須要小於視口大小減去from本身的元素寬高。

具體代碼:

move:function(event){var e = event ? event : window.event;var dBox=ReactDOM.findDOMNode(this.refs.dragBox);if (this.state.flag) {var nowX = e.clientX, nowY = e.clientY;var disX = nowX - this.state.currentX, disY = nowY - this.state.currentY;/*增加拖拽範圍檢測*/var currentLeft=parseInt(this.state.left) + disX;var currentTop=parseInt(this.state.top) + disY;var docX=document.documentElement.clientWidth||document.body.clientWidth;var docY=document.documentElement.clientHeight||document.body.clientHeight;if(currentLeft<=250){//檢測螢幕左邊,因為我這裡的初始置中是利用了負1/2的盒子寬度的margin,所以用250px判斷邊界dBox.style.left=250+"px";}else if(currentLeft>=(docX-dBox.offsetWidth+250)){ //檢測右邊dBox.style.left=(docX-this.state.offsetX)+"px";}else{dBox.style.left =currentLeft+ "px";}if(currentTop<=200){ //檢測螢幕上邊,因為我這裡的初始置中是利用了負1/2的盒子高度的margin,所以用200px判斷邊界 <br> dBox.style.top=200+"px"; <br> }else if(currentTop>=(docY-dBox.offsetHeight+200)){ //檢測下邊<br> dBox.style.top=(docY-this.state.offsetY)+"px";<br> }else{<br> dBox.style.top = currentTop + "px"; <br> }<br> }

PS:新的代碼已經更新在我的github上面,大家可以研究一下。

ReactJS的背景和原理

在Web開發中,我們總需要將變化的資料即時反應到UI上,這時就需要對DOM進行操作。而複雜或頻繁的DOM操作通常是效能瓶頸產生的原因(如何進行高效能的複雜DOM操作通常是衡量一個前端開發人員技能的重要指標)。React為此引入了虛擬DOM(Virtual DOM)的機制:在瀏覽器端用Javascript實現了一套DOM API。基於React進行開發時所有的DOM構造都是通過虛擬DOM進行,每當資料變化時,React都會重新構建整個DOM樹,然後React將當前整個DOM樹和上一次的DOM樹進行對比,得到DOM結構的區別,然後僅僅將需要變化的部分進行實際的瀏覽器DOM更新。而且React能夠批處理虛擬DOM的重新整理,在一個事件迴圈(Event Loop)內的兩次資料變化會被合并,例如你連續的先將節點內容從A變成B,然後又從B變成A,React會認為UI不發生任何變化,而如果通過手動控制,這種邏輯通常是極其複雜的。儘管每一次都需要構造完整的虛擬DOM樹,但是因為虛擬DOM是記憶體資料,效能是極高的,而對實際DOM進行操作的僅僅是Diff部分,因而能達到提高效能的目的。這樣,在保證效能的同時,開發人員將不再需要關注某個資料的變化如何更新到一個或多個具體的DOM元素,而只需要關心在任意一個資料狀態下,整個介面是如何Render的。

如果你像在90年代那樣寫過伺服器端Render的純Web頁面那麼應該知道,伺服器端所要做的就是根據資料Render出HTML送到瀏覽器端。如果這時因為使用者的一個點擊需要改變某個狀態文字,那麼也是通過重新整理整個頁面來完成的。伺服器端並不需要知道是哪一小段HTML發生了變化,而只需要根據資料重新整理整個頁面。換句話說,任何UI的變化都是通過整體重新整理來完成的。而React將這種開發模式以高效能的方式帶到了前端,每做一點介面的更新,你都可以認為重新整理了整個頁面。至於如何進行局部更新以保證效能,則是React架構要完成的事情。

借用Facebook介紹React的視頻中聊天應用的例子,當一條新的訊息過來時,傳統開發的思路如上圖,你的開發過程需要知道哪條資料過來了,如何將新的DOM結點添加到當前DOM樹上;而基於React的開發思路如下圖,你永遠只需要關心資料整體,兩次資料之間的UI如何變化,則完全交給架構去做。可以看到,使用React大大降低了邏輯複雜性,意味著開發難度降低,可能產生Bug的機會也更少。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.