Vue で Sortable を使用する手順の詳細な説明

php中世界最好的语言
リリース: 2018-05-02 10:32:53
オリジナル
4533 人が閲覧しました

今回は、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 ノードが実際の DOM である $A に更新されます。

[$A,$B,$C,$D]

に戻っているため、更新されるという問題があります。ドラッグ後のパッチ アルゴリズムによる操作パスは、

ドラッグで実際の DOM を移動 -> データ配列を操作 -> パッチ アルゴリズムで実際の DOM を更新する

根本的な原因は、仮想 DOM と実際の DOM の間の不一致です。

Vue2.0 以前では、Virtual DOM が導入されていなかったため、この問題は存在しませんでした。

Vue フレームワークを使用する場合は、DOM

Solution

1 を直接操作しないようにしてください。これは、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] に復元します。 DOM 操作を Vue に戻します

実際の 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 に関する他の関連記事に注目してください。中国語のサイトです!

推奨読書:

vue-cli クロスドメインリクエストの作り方

Angular コンポーネントタグにスタイルクラスを追加するための 5 ステップの手順

JS が演算子のオーバーロードを実装する方法

以上がVue で Sortable を使用する手順の詳細な説明の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

関連ラベル:
ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート
私たちについて 免責事項 Sitemap
PHP中国語ウェブサイト:福祉オンライン PHP トレーニング,PHP 学習者の迅速な成長を支援します!