Vue+ソータブルを使用する

Jun 11, 2018 am 10:54 AM
vue

今回は、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 をドラッグして移動 -> データ配列を操作 -> パッチ アルゴリズムで実際の DOM を更新します

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

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

Vue フレームワークを使用する場合は、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 に関する他の関連記事に注目してください。中国語のサイトです!

推奨読書:

Vue+Nuxt.jsでサーバーサイドレンダリングを行う

AngularはHMRコード分析を使用する

vueを使用してモバイルドロップダウンリストを作成する

以上がVue+ソータブルを使用するの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover

AI Clothes Remover

写真から衣服を削除するオンライン AI ツール。

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

AI Hentai Generator

AI Hentai Generator

AIヘンタイを無料で生成します。

ホットツール

メモ帳++7.3.1

メモ帳++7.3.1

使いやすく無料のコードエディター

SublimeText3 中国語版

SublimeText3 中国語版

中国語版、とても使いやすい

ゼンドスタジオ 13.0.1

ゼンドスタジオ 13.0.1

強力な PHP 統合開発環境

ドリームウィーバー CS6

ドリームウィーバー CS6

ビジュアル Web 開発ツール

SublimeText3 Mac版

SublimeText3 Mac版

神レベルのコード編集ソフト(SublimeText3)

vueでechartを使用する方法 vueでechartを使用する方法 May 09, 2024 pm 04:24 PM

Vue で ECharts を使用すると、アプリケーションにデータ視覚化機能を簡単に追加できます。具体的な手順には、ECharts および Vue ECharts パッケージのインストール、ECharts の導入、チャート コンポーネントの作成、オプションの構成、チャート コンポーネントの使用、Vue データに対応したチャートの作成、対話型機能の追加、および高度な使用法の使用が含まれます。

vue におけるエクスポートのデフォルトの役割 vue におけるエクスポートのデフォルトの役割 May 09, 2024 pm 06:48 PM

質問: Vue におけるエクスポートのデフォルトの役割は何ですか?詳細説明: エクスポートデフォルトは、コンポーネントのデフォルトのエクスポートを定義します。インポートすると、コンポーネントが自動的にインポートされます。インポートプロセスを簡素化し、明確さを改善し、競合を防ぎます。一般に、名前付きエクスポートとデフォルト エクスポートの両方を使用して、個々のコンポーネントをエクスポートし、グローバル コンポーネントを登録するために使用されます。

vueでのmap関数の使い方 vueでのmap関数の使い方 May 09, 2024 pm 06:54 PM

Vue.js マップ関数は、各要素が元の配列の各要素の変換結果である新しい配列を作成する組み込みの高階関数です。構文は、map(callbackFn) です。callbackFn は、配列内の各要素を最初の引数として受け取り、オプションでインデックスを 2 番目の引数として受け取り、値を返します。 map 関数は元の配列を変更しません。

vueのeventと$eventの違い vueのeventと$eventの違い May 08, 2024 pm 04:42 PM

Vue.js では、event はブラウザによってトリガーされるネイティブ JavaScript イベントですが、$event は Vue コンポーネントで使用される Vue 固有の抽象イベント オブジェクトです。 $event はデータ バインディングをサポートするようにフォーマットおよび拡張されているため、一般に $event を使用する方が便利です。ネイティブ イベント オブジェクトの特定の機能にアクセスする必要がある場合は、event を使用します。

Vue における onmounted の役割 Vue における onmounted の役割 May 09, 2024 pm 02:51 PM

onMounted は、Vue のコンポーネント マウント ライフ サイクル フックです。その機能は、コンポーネントが DOM にマウントされた後に、DOM 要素への参照の取得、データの設定、HTTP リクエストの送信、イベント リスナーの登録などの初期化操作を実行することです。コンポーネントが更新された後、またはコンポーネントが破棄される前に操作を実行する必要がある場合は、他のライフサイクル フックを使用できます。

vueのエクスポートとデフォルトのエクスポートの違い vueのエクスポートとデフォルトのエクスポートの違い May 08, 2024 pm 05:27 PM

Vue.js でモジュールをエクスポートするには、エクスポートとデフォルトのエクスポートの 2 つの方法があります。 export は名前付きエンティティのエクスポートに使用され、中括弧の使用が必要です。export default はデフォルト エンティティのエクスポートに使用され、中括弧は必要ありません。インポートする場合、エクスポートによってエクスポートされたエンティティはその名前を使用する必要がありますが、エクスポートのデフォルトによってエクスポートされたエンティティは暗黙的に使用できます。複数回インポートする必要があるモジュールにはデフォルトのエクスポートを使用し、一度だけエクスポートするモジュールにはエクスポートを使用することをお勧めします。

Vueのフックとは何ですか Vueのフックとは何ですか May 09, 2024 pm 06:33 PM

Vue フックは、特定のイベントまたはライフサイクル ステージでアクションを実行するコールバック関数です。これらには、ライフサイクル フック (beforeCreate、mounted、beforeDestroy など)、イベント処理フック (クリック、入力、キーダウンなど)、およびカスタム フックが含まれます。フックはコンポーネントの制御を強化し、コンポーネントのライフサイクルに対応し、ユーザーの操作を処理し、コンポーネントの再利用性を向上させます。フックを使用するには、フック関数を定義し、ロジックを実行してオプションの値を返すだけです。

vue のイベント修飾子はどのようなシナリオに使用できますか? vue のイベント修飾子はどのようなシナリオに使用できますか? May 09, 2024 pm 02:33 PM

Vue.js イベント修飾子は、次のような特定の動作を追加するために使用されます。 デフォルト動作の防止 (.prevent) イベント バブリングの停止 (.stop) ワンタイム イベント (.once) イベントのキャプチャ (.capture) パッシブ イベント リスニング (.passive) アダプティブ修飾子 (.self)キー修飾子 (.key)

See all articles