Home > Article > Web Front-end > Let’s talk again about a series of problems caused by React.js’s implementation of native js drag and drop effects_javascript skills
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: The new code has been updated on my github, you can study it.
Background and principles of ReactJS
In web development, we always need to reflect changing data to the UI in real time, and then we need to operate the DOM. Complex or frequent DOM operations are usually the cause of performance bottlenecks (how to perform high-performance complex DOM operations is usually an important indicator of a front-end developer's skills). React introduces a virtual DOM (Virtual DOM) mechanism for this purpose: a set of DOM API is implemented on the browser side using Javascript. When developing based on React, all DOM construction is performed through virtual DOM. Whenever the data changes, React will rebuild the entire DOM tree. Then React compares the current entire DOM tree with the previous DOM tree to obtain the DOM structure. Difference, and then only the parts that need to change are updated in the actual browser DOM. Moreover, React can batch refresh the virtual DOM. Two data changes in an event loop (Event Loop) will be merged. For example, if you continuously change the node content from A to B, and then from B to A, React will think that the UI has not changed, and if controlled manually, this logic is usually extremely complicated. Although a complete virtual DOM tree needs to be constructed every time, because the virtual DOM is memory data, the performance is extremely high, and only the Diff part is operated on the actual DOM, thus improving performance. In this way, while ensuring performance, developers no longer need to pay attention to how a certain data change is updated to one or more specific DOM elements, but only need to care about how the entire interface is rendered in any data state.
If you have written a pure Web page with server-side Rendering like you did in the 1990s, then you should know that all the server-side has to do is render HTML based on the data and send it to the browser. If a certain status text needs to be changed due to a user click, this can also be done by refreshing the entire page. The server does not need to know which small piece of HTML has changed, but only needs to refresh the entire page based on the data. In other words, any UI changes are done through an overall refresh. React brings this development model to the front end in a high-performance way. Every time you update the interface, you can think that the entire page has been refreshed. As for how to perform partial updates to ensure performance, that is what the React framework has to do.
Borrowing the example of the chat application in Facebook’s video introducing React. When a new message comes, the traditional development idea is as shown above. Your development process needs to know which piece of data has come and how to add a new DOM node. to the current DOM tree; and the development idea based on React is as shown below. You only need to care about the overall data. How the UI changes between the two data is completely left to the framework. It can be seen that using React greatly reduces the logic complexity, which means that development difficulty is reduced and there are fewer opportunities for bugs to occur.