這次帶給大家怎麼在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變成
##此時我們只操作了真實DOM,改編了它的位置,而Virtual Dom的結構並沒有改變,依然是[$B,$A,$C,$D]
[{elm:$A,data:'A'},#此時我們把列表元素也依照真實DOM排序後變成{elm :$B,data:'B'},
{elm:$C,data:'C'},
{elm:$D,data:'D'}]
['B','A','C','D']#這時候根據Diff演算法,計算出來的Patch為,VNode前兩項是同類型的節點,所以直接更新,也就是把$A節點更新成$B,把$B節點更新成$ A,真實DOM又變回了
[$A,$B,$C,$D]所以就出現了拖曳之後又被Patch演算法更新了一次的問題,操作路徑可以簡單理解為拖曳移動真實DOM -> 操作資料數組-> Patch演算法再更新真實DOM
#根本原因
根本原因是Virtual DOM和真實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中文網其他相關文章!

從C/C 轉向JavaScript需要適應動態類型、垃圾回收和異步編程等特點。 1)C/C 是靜態類型語言,需手動管理內存,而JavaScript是動態類型,垃圾回收自動處理。 2)C/C 需編譯成機器碼,JavaScript則為解釋型語言。 3)JavaScript引入閉包、原型鍊和Promise等概念,增強了靈活性和異步編程能力。

不同JavaScript引擎在解析和執行JavaScript代碼時,效果會有所不同,因為每個引擎的實現原理和優化策略各有差異。 1.詞法分析:將源碼轉換為詞法單元。 2.語法分析:生成抽象語法樹。 3.優化和編譯:通過JIT編譯器生成機器碼。 4.執行:運行機器碼。 V8引擎通過即時編譯和隱藏類優化,SpiderMonkey使用類型推斷系統,導致在相同代碼上的性能表現不同。

JavaScript在現實世界中的應用包括服務器端編程、移動應用開發和物聯網控制:1.通過Node.js實現服務器端編程,適用於高並發請求處理。 2.通過ReactNative進行移動應用開發,支持跨平台部署。 3.通過Johnny-Five庫用於物聯網設備控制,適用於硬件交互。

我使用您的日常技術工具構建了功能性的多租戶SaaS應用程序(一個Edtech應用程序),您可以做同樣的事情。 首先,什麼是多租戶SaaS應用程序? 多租戶SaaS應用程序可讓您從唱歌中為多個客戶提供服務

本文展示了與許可證確保的後端的前端集成,並使用Next.js構建功能性Edtech SaaS應用程序。 前端獲取用戶權限以控制UI的可見性並確保API要求遵守角色庫

JavaScript是現代Web開發的核心語言,因其多樣性和靈活性而廣泛應用。 1)前端開發:通過DOM操作和現代框架(如React、Vue.js、Angular)構建動態網頁和單頁面應用。 2)服務器端開發:Node.js利用非阻塞I/O模型處理高並發和實時應用。 3)移動和桌面應用開發:通過ReactNative和Electron實現跨平台開發,提高開發效率。

JavaScript的最新趨勢包括TypeScript的崛起、現代框架和庫的流行以及WebAssembly的應用。未來前景涵蓋更強大的類型系統、服務器端JavaScript的發展、人工智能和機器學習的擴展以及物聯網和邊緣計算的潛力。

JavaScript是現代Web開發的基石,它的主要功能包括事件驅動編程、動態內容生成和異步編程。 1)事件驅動編程允許網頁根據用戶操作動態變化。 2)動態內容生成使得頁面內容可以根據條件調整。 3)異步編程確保用戶界面不被阻塞。 JavaScript廣泛應用於網頁交互、單頁面應用和服務器端開發,極大地提升了用戶體驗和跨平台開發的靈活性。


熱AI工具

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

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

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

AI Hentai Generator
免費產生 AI 無盡。

熱門文章

熱工具

Dreamweaver CS6
視覺化網頁開發工具

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

DVWA
Damn Vulnerable Web App (DVWA) 是一個PHP/MySQL的Web應用程序,非常容易受到攻擊。它的主要目標是成為安全專業人員在合法環境中測試自己的技能和工具的輔助工具,幫助Web開發人員更好地理解保護網路應用程式的過程,並幫助教師/學生在課堂環境中教授/學習Web應用程式安全性。 DVWA的目標是透過簡單直接的介面練習一些最常見的Web漏洞,難度各不相同。請注意,該軟體中

MinGW - Minimalist GNU for Windows
這個專案正在遷移到osdn.net/projects/mingw的過程中,你可以繼續在那裡關注我們。 MinGW:GNU編譯器集合(GCC)的本機Windows移植版本,可自由分發的導入函式庫和用於建置本機Windows應用程式的頭檔;包括對MSVC執行時間的擴展,以支援C99功能。 MinGW的所有軟體都可以在64位元Windows平台上運作。

SecLists
SecLists是最終安全測試人員的伙伴。它是一個包含各種類型清單的集合,這些清單在安全評估過程中經常使用,而且都在一個地方。 SecLists透過方便地提供安全測試人員可能需要的所有列表,幫助提高安全測試的效率和生產力。清單類型包括使用者名稱、密碼、URL、模糊測試有效載荷、敏感資料模式、Web shell等等。測試人員只需將此儲存庫拉到新的測試機上,他就可以存取所需的每種類型的清單。