今回は、Vue で Sortable を使用する方法と、Vue で Sortable を使用する際の注意点について説明します。以下は実際の事例です。
私は以前、コンポーネント ライブラリ Vue と Element-UI を使用したバックエンド管理システムを開発しました。非常に興味深い問題に遭遇したので、それを共有したいと思います。
リスト表示ページでは、Element-UIのテーブルコンポーネントを使用しました。新しい要件は、元のテーブルに基づいたドラッグアンドドロップの並べ替えをサポートすることです。しかし、元のコンポーネント自体はドラッグ&ドロップによるソートに対応しておらず、Element-UIから直接導入しているためソースコードの修正が不便で、DOMを直接操作するしか方法がありません。
具体的な方法は、マウントされたライフサイクル関数で this.$el に対して実際の DOM 操作を実行し、一連のドラッグ イベントをリッスンし、イベント コールバックで DOM を移動し、データを更新することです。
Touch イベントに似た HTML5 の Drag イベントが多数あり、手動で実装することもできますが、ここでは、オープンソースの Sortable ライブラリを直接渡して、カプセル化されたイベントを監視します。 Vue の開発モデルに従って、モバイル DOM のコールバックで実際のデータ データを更新して、データと DOM の間の一貫性を維持します。
これで終わりだと思ったら、それは完全に間違いです。遅かれ早かれ、盗んだ怠惰を返さなければなりません。 。 。この解決策は素晴らしいと思いましたが、デバッグしようと思った瞬間、奇妙な現象が発生しました。A と B をドラッグして交換した後、B と A が魔法のように再び交換されてしまいました。これはどうなっているでしょうか?実際の DOM を移動した後、データ配列の順序とレンダリングされた DOM の順序も一致するはずです。
何が問題ですか? Vue の実装原理を思い出してください。Vue2.0 より前では、双方向バインディングは、defineProperty 依存関係の挿入と追跡によって実現されていました。 v-for 配列命令では、一意の Key が指定されている場合、配列内の要素の差分が効率的な Diff アルゴリズムによって計算され、最小限の移動または削除操作が実行されます。 Vue 2.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 を操作してその位置を調整するだけであり、仮想 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 の最初の 2 つの項目は同じ種類のノードであるため、直接更新されます。 $A ノードは $B に更新され、$B ノードは $ A に更新され、実際の DOM は
[$A,$B,$C,$D]
に戻りました。
の実DOMをドラッグして移動→Patchアルゴリズムで更新するという問題です。
根本原因
根本原因は、仮想 DOM と実際の DOM の間の不一致です。ソリューション
1. キーを設定して各 VNode を一意にマークします。これは、Vue が v-for 命令を使用することを推奨する方法でもあります。 2つのVNodeが同じ型かどうかを判定する際にはsameVnodeメソッドが呼び出されるため、キーが同じかどうかの判定が優先される
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] に復元し、 Vue への DOM 操作
実際の DOM をドラッグして移動します -> 移動操作を復元します -> データ配列を操作します -> パッチ アルゴリズムにより実際の 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 . 暴力解決!パッチ更新なしで、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 中国語 Web サイトの他の関連記事に注目してください。
推奨読書:
nodejsを操作してレスポンスライトバックを通じてページリソースをレンダリングする方法
websocketを使用するためにnodejsを操作する方法
以上がVue でソート可能を使用する方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。