這次帶給大家Vue Sortable專案實戰程式碼,Vue Sortable專案實戰的注意事項有哪些,以下就是實戰案例,一起來看一下。
之前開發一個後台管理系統,裡面用到了Vue和Element-UI這個元件庫,遇到一個蠻有意思的問題,跟大家分享一下。
場景是這樣,在一個清單展示頁上,我使用了Element-UI的表格元件,新的需求是在原始表格的基礎上支援拖曳排序。但是原有的元件本身不支援拖曳排序,而且由於是直接引入的Element-UI,不方便修改它的原始碼,所以比較可行的方法只能是直接操作DOM。
具體的做法是在mounted生命週期函數裡,對this.$el進行真實DOM的操作,監聽drag的一系列事件,在事件回調裡移動DOM,並更新data。
HTML5 Drag事件還是挺多的,和Touch事件差不多,自己手工實現也可以,不過這裡就偷了個懶,直接用了一個開源的Sortable庫,直接傳入this.$el,監聽封裝後的回調,並且根據Vue的開發模式,在行動DOM的回呼裡更新實際的Data數據,保持數據和DOM的一致性。
如果你以為到這就結束了,那就大錯特錯,偷過的懶遲早要還。 。 。本來以為這個方案是很美好的,沒想到剛想調試一下,就出現了詭異的現象:A和B拖曳交換位置之後,B和A又神奇得換回去了!這是怎麼回事?似乎我們的操作沒有什麼問題,在真實DOM移動了之後,我們也移動了對應的data,資料數組的順序和渲染出DOM的順序應該是一致的。
問題出在哪裡?我們回想Vue的實作原理,在Vue2.0之前是透過defineProperty依賴注入和追蹤的方式實現雙向綁定。針對v-for數組指令,如果指定了唯一的Key,則會透過高效率的Diff演算法計算出數組內元素的差異,進行最少的移動或刪除操作。而Vue2.0之後在引入了Virtual Dom之後,Children元素的Dom Diff演算法和前者其實是相似的,唯一的差別就是,2.0之前Diff直接針對v-for指令的數組對象,2.0之後則是針對Virtual Dom。 DOM Diff演算法在這裡不再贅述,這裡解釋的比較清楚virtual-dom diff演算法
#假設我們的列表元素數組是
['A','B', 'C','D']
渲染出來後的DOM節點是
[$A,$B,$C,$D]
那麼Virtual Dom對應的結構就是
[{elm:$A,data:'A'},
{elm:$B,data:'B'} ,
{elm:$C,data:'C'},
{elm:$D,data:'D'}]
假設拖曳排序之後,真實的DOM變成
[$B,$A,$C,$D]
#此時我們只操作了真實DOM,改編了它的位置,而Virtual Dom的結構並沒有改變,依然是
[{elm:$A,data:'A'},
{elm:$B,data:'B'},
{elm:$C,data:'C'},
{elm:$D,data:'D'}]
此時我們把清單元素也依照真實DOM排序後變成
['B','A','C','D']
這時候根據Diff演算法,計算出的Patch為,VNode前兩項是同類型的節點,所以直接更新,也就是把$A節點更新成$B,把$B節點更新成$A,真實DOM又變回了
[ $A,$B,$C,$D]
所以就出現了拖曳之後又被Patch演算法更新了一次的問題,操作路徑可以簡單理解為
拖曳移動真實DOM -> 操作資料數組-> Patch演算法再更新真實DOM
根本原因
##根本原因是Virtual DOM和真實DOM之間出現了不一致。 所以在Vue2.0以前,因為沒有引入Virtual DOM,這個問題是不存在的。 在使用Vue框架的時候要盡量避免直接操作DOM解決方案
1、透過設定key唯一標誌每一個VNode,這也是Vue推薦的使用v-for指令的方式。因為在判斷兩個VNode是否為相同類型時會呼叫sameVnode方法,優先判斷key是否相同
function sameVnode (a, b) { return ( a.key === b.key && a.tag === b.tag && a.isComment === b.isComment && isDef(a.data) === isDef(b.data) && sameInputType(a, b) ) }
2、因為根本原因是真實DOM和VNode不一致,所以可以透過把拖曳移動真實DOM的運算還原,也就是在回呼函數裡,把[$B,$A,$C,$D]還原成[$A,$B,$C,$D],讓DOM的運算交還給Vue
拖曳移動真實DOM ->還原移動操作-> 操作資料數組-> Patch演算法再更新真實DOM
程式碼如下
var app = new Vue({ el: '#app', mounted:function(){ var $ul = this.$el.querySelector('#ul') var that = this new Sortable($ul, { onUpdate:function(event){ var newIndex = event.newIndex, oldIndex = event.oldIndex $li = $ul.children[newIndex], $oldLi = $ul.children[oldIndex] // 先删除移动的节点 $ul.removeChild($li) // 再插入移动的节点到原有节点,还原了移动的操作 if(newIndex > oldIndex) { $ul.insertBefore($li,$oldLi) } else { $ul.insertBefore($li,$oldLi.nextSibling) } // 更新items数组 var item = that.items.splice(oldIndex,1) that.items.splice(newIndex,0,item[0]) // 下一个tick就会走patch更新 } }) }, data:function() { return { message: 'Hello Vue!', items:[{ key:'1', name:'1' },{ key:'2', name:'2' },{ key:'3', name:'3' },{ key:'4', name:'4' }] } }, watch:{ items:function(){ console.log(this.items.map(item => item.name)) } } })
3.暴力解決!不走patch更新,透過v-if設置,直接重新渲染一遍。當然不建議這麼做,只是提供這種思路~
mounted:function(){ var $ul = this.$el.querySelector('#ul') var that = this var updateFunc = function(event){ var newIndex = event.newIndex, oldIndex = event.oldIndex var item = that.items.splice(oldIndex,1) that.items.splice(newIndex,0,item[0]) // 暴力重新渲染! that.reRender = false // 借助nextTick和v-if重新渲染 that.$nextTick(function(){ that.reRender = true that.$nextTick(function(){ // 重新渲染之后,重新进行Sortable绑定 new Sortable(that.$el.querySelector('#ul'), { onUpdate:updateFunc }) }) }) } new Sortable($ul, { onUpdate:updateFunc }) },
所以,我們平時在使用框架的時候,也要去了解框架的實現原理的,否則遇到一些棘手的情況就會無從下手~
相信看了本文案例你已經掌握了方法,更多精彩請關注php中文網其它相關文章!
推薦閱讀:
#以上是Vue+Sortable專案實戰程式碼的詳細內容。更多資訊請關注PHP中文網其他相關文章!

vue中props可以传递函数;vue中可以将字符串、数组、数字和对象作为props传递,props主要用于组件的传值,目的为了接收外面传过来的数据,语法为“export default {methods: {myFunction() {// ...}}};”。

本篇文章带大家聊聊vue指令中的修饰符,对比一下vue中的指令修饰符和dom事件中的event对象,介绍一下常用的事件修饰符,希望对大家有所帮助!

如何覆盖组件库样式?下面本篇文章给大家介绍一下React和Vue项目中优雅地覆盖组件库样式的方法,希望对大家有所帮助!

react与vue的虚拟dom没有区别;react和vue的虚拟dom都是用js对象来模拟真实DOM,用虚拟DOM的diff来最小化更新真实DOM,可以减小不必要的性能损耗,按颗粒度分为不同的类型比较同层级dom节点,进行增、删、移的操作。


熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

AI Hentai Generator
免費產生 AI 無盡。

熱門文章

熱工具

EditPlus 中文破解版
體積小,語法高亮,不支援程式碼提示功能

Safe Exam Browser
Safe Exam Browser是一個安全的瀏覽器環境,安全地進行線上考試。該軟體將任何電腦變成一個安全的工作站。它控制對任何實用工具的訪問,並防止學生使用未經授權的資源。

mPDF
mPDF是一個PHP庫,可以從UTF-8編碼的HTML產生PDF檔案。原作者Ian Back編寫mPDF以從他的網站上「即時」輸出PDF文件,並處理不同的語言。與原始腳本如HTML2FPDF相比,它的速度較慢,並且在使用Unicode字體時產生的檔案較大,但支援CSS樣式等,並進行了大量增強。支援幾乎所有語言,包括RTL(阿拉伯語和希伯來語)和CJK(中日韓)。支援嵌套的區塊級元素(如P、DIV),

SublimeText3 Mac版
神級程式碼編輯軟體(SublimeText3)

MantisBT
Mantis是一個易於部署的基於Web的缺陷追蹤工具,用於幫助產品缺陷追蹤。它需要PHP、MySQL和一個Web伺服器。請查看我們的演示和託管服務。