Svelte の Defer Transition を Vue で実装する方法

Svelte の Defer Transition を Vue で実装する方法

最近、Rich Harris の <Rethinking Reactivity> ビデオを視聴しました。Svelte フレームワークの効率性に驚き、Vue にはないアニメーションのネイティブ サポート (遅延遷移) があることを発見しました。

まず、Svelte のいわゆる defer 遷移の効果を見てみましょう。

これは Svelte で作成された Todo デモ アプリです。全体のToDoは3つの部分に分かれています。入力セクション、ToDo リスト、完了リスト。 ToDo リスト内の項目をクリックすると、対応する項目が完了リストに「移動」され、その逆も同様です。

ここで、アイテムは 1 つのリストから別のリストに転送されますが、突然点滅するのではなく、クリック ポイントから宛先まで非常にスムーズに移動されます。同時に、リスト内のアイテムがなくなると、残りのアイテムがスムーズに上に移動し、空いた位置を埋めます。 Svelte では、数行のコードを追加するだけでこれを実現できるため、開発者にとって非常に使いやすく効率的です。 以下のコードまたはSvelteチュートリアルを参照してください

{#各 todos.filter(t => !t.done) を todo (todo.id) として}
    <ラベル
	in:receive="{{キー: todo.id}}"
        out:send="{{key: todo.id}}"
        アニメーション:反転>
        <input type=checkbox on:change={() => mark(todo, true)}>
            {todo.説明}
            <button on:click="{() => remove(todo)}">削除</button>
    </ラベル>
{/それぞれ}

要素には in、out、animate 属性のみが追加されます。ここで、in と out はそれぞれフレームワークによって提供される関数の受信と送信を受け入れ、それらに対してフィルタリング条件を提供します。 animate プロパティは組み込みの flip メソッドを受け入れます。ここでの flip は反転を意味するのではなく、vue が <transition-group> でも使用する FLIP テクノロジーを意味します。主に、リスト内の残りの項目全体を移動して、失われた要素の位置を埋めるために使用されます。

そこで、Vue であれば、対応する効果をどのように実現できるかを考えました。 (詳しい説明を読みたくない場合は、コードペンでコードを直接表示できます)

Vue は、アニメーションをサポートする 2 つのコンポーネントをネイティブに提供します。遷移と遷移グループ。リストの移動なので、ここでは transition-group を使用します。具体的な使用方法については、Vue チュートリアルの「トランジションとアニメーション」を参照してください。

同じ効果を実現するには、2 つの主要な UI アニメーション効果を実装する必要があります。

リスト内の項目が消えると、残りの項目が移動して空きスペースを埋めます。項目が消えて別のリストに挿入されると、その項目が移動します。最初の要件は実装が比較的簡単です。Vue ネイティブではすでに優れたサポートが提供されています。Vue ドキュメントの List-Move-Transitions を参照してください。

2 番目の要件を達成するには、いくつかの問題を解決する必要があります。

  1. 消失した物品の位置情報
  2. エントリの位置情報を挿入
  3. アニメーションの開始と終了のタイミング

まず最初の 2 つの問題を解決する方法を見てみましょう。ドキュメントによると、transition-group は JavaScript フックを提供します。彼らです:

 v-on:入力前
 v-on:入力
 v-on:後入力
 v-on:入力キャンセル

 v-on:退出前
 v-on: 離れる
 v-on:退出後
 v-on:退会キャンセル

視覚化すると次のようになります。

before-enter: エントリを挿入するための遷移の初期値を設定するために使用されます。 BoundingClientRect を取得できません。現時点ではアニメーション期間を入力してください。このとき、enterフック関数のパラメータelはboundingClientRectを取得できる after-enter:アニメーション終了後のコールバック関数 enter-cancelled:enterフックをキャンセルする

休暇についても同様です。

したがって、エントリ要素の DOMRect 情報を取得できるのは、エントリするときとエントリを離れるときだけです。

このようにして、退出アイテムの DOMRect データを取得し、退出時に保存することができます。入場時には退出項目と入場項目の両方の位置情報を取得できます。

位置情報は取得できたのですが、エントリーを入力した際に消えたエントリーから移動させるにはどうしたらよいでしょうか? (まずは考えてから、以下の説明を読んでください)。

したがって、移動の効果を実現したい場合は、まずLeave項目要素を非表示にする必要があります。

残す(el, 完了) {
      console.log("出発前");
      定数 rect = el.getBoundingClientRect();
      rectMap を el.dataset.key に設定して送信します。
      el.style.display = "なし";
},

次に、Enter 項目要素の初期位置状態を設定します。初期位置は、Leave 項目要素の位置です。その後、遷移が有効になったら、その位置を挿入 (Enter) 位置に戻します。

この方法は、実際にはいわゆる FLIP テクノロジーです。この手法は、削除された項目を埋めるために残りのリストを移動するために、 transition-group コンポーネントでも使用されます。

var first = el.getBoundingClientRect();

// ここで要素を最後の位置に設定します。
el.classList.add('totes-at-the-end');

// 再度読み込みます。これにより同期が強制されます
// レイアウトなので注意してください。
var last = el.getBoundingClientRect();

// 他の計算結果に対してもこれを行うことができます
// 必要に応じてスタイルも変更します。
// 必ずコンポジターのみを使用するようにしてください
// 変換や不透明度などのプロパティ
// 可能な場合は。
var invert = first.top - last.top;

// 反転します。
el.style.transform =
    `translateY(${invert}px)`;

// 次のフレームを待って
// すべてのスタイル変更を知る
// 保留中。
リクエストアニメーションフレーム(関数() {

  // アニメーションをオンにします。
  el.classList.add('変換時にアニメーション化');

  // ゴー、ゴー、ゴーーーー!
  el.style.transform = '';
});

次に、エントリ要素の遷移の初期状態をいつ設定するか、およびエントリ要素の遷移の終了状態をいつ設定するかという疑問が生じます。

上記の JavaScript フックに従って、before-enter フック関数で初期状態を設定し、enter フック関数で遷移終了状態を設定できます。では、初期状態は何でしょうか? getBoundingClientRect を使用すると、上、左、下、右、幅、高さ、x、y を含む、enter 要素 (後で to によって識別されます) の DOMRect データを取得できます。 同時に、以前に保存した休暇位置マップを通じて、休暇エントリ(呼び出し元)の位置情報も取得できます。したがって、before-enter では、計算されたオフセットを使用して、translate を通じて to 要素の位置を初期化します。次に、enter ステージでその値を from に変換し、CSS に transition を追加します。

before-enter フック内:

        // モバイル要素の識別子 const key = el.dataset.key;
        // エントリマップを入力します。ここで、before-enterフックに注意してください。
        //receiveRectMap にアクセスできません。特別な取り扱いが必要です。後ほど、const to = receiveRectMap.get(key); について説明します。
        //エントリマップを残す
        const from = sendRectMap.get(キー);

        // オフセットを計算します const dx = from.left - to.left;
        定数 dy = from.top - to.top;
        
        // to 項目の位置を初期化します el.style.transform = `translate(${dx}px, ${dy}px)`;
        el.style.opacity = 0;

入力フック内:

        el.style.transition = "すべて 800ms";
        el.style.transform = "";
        el.style.opacity = 1;
        el.style.display = "ブロック";

上記のコードでは、before-enter で、receiveRectMap.get(key) を通じて to が取得されます。ただし、この時点では、receiveRectMap 内のキーに対応する DOMRect 値はありません。 before-enterの入力パラメータはel(HTMLElement)ですが、el要素のDOMRect内の値は全て0なので、enterメソッド内のreceiveRectMapにelを入れる必要があります。これにより矛盾が発生します。つまり、before-enter の translate を通じて to 要素の位置を初期化することはできません。したがって、ここでは遷移の発生を遅らせるために遅延遷移手法を使用します。

遅延遷移を実装するには、enter で setTimeout または requestAnimationFrame を使用できます。

リクエストアニメーションフレーム(() => {
        定数キー = el.dataset.key;
		  // このようにして、receiveRectMap にはキーの値が含まれます。
        定数 to = 受信RectMap.get(キー);
        const from = sendRectMap.get(キー);

        定数 dx = from.left - to.left;
        定数 dy = from.top - to.top;

        // 移行を遅らせたので、
        // つまり、to要素の位置は実際に宛先の位置に到達したことになります。
        // そのため、transition を使用して手動で from の位置に遷移する必要があります。この行は非常に重要です el.style.transition = "all 0ms";
        el.style.transform = `translate(${dx}px, ${dy}px)`;
        
        // 初期化後、次のアニメーション フレームで FLIP テクノロジーを使用して元の位置に戻します。
	リクエストアニメーションフレーム(() => {
          el.style.transition = "すべて 800ms";
          el.style.transform = "";
          el.style.opacity = 1;
          el.style.display = "ブロック";
        });
      });

完全なコードはcodepenで見つかります

最終結果:

以上が、Svelte の Defer Transition を Vue で実装する方法の詳細です。Svelte の Defer Transition の Vue での実装の詳細については、123WORDPRESS.COM の他の関連記事に注目してください。

以下もご興味があるかもしれません:
  • アニメーション効果のようなVueトランジションの例
  • Vue トランジション効果の CSS トランジションの詳細説明 (transition、animation、animate.css との組み合わせ)
  • Vueで再利用可能なトランジションを作成する方法
  • シンプルで簡単なJavaScript開発のためのSvelte実装原理の詳細な説明

<<:  nginx 設定チュートリアルにおける add_header の落とし穴の詳細な説明

>>:  sqlite を mysql スクリプトに移行する方法

推薦する

MYSQL(電話番号、IDカード)データ非感応化の実装

1. データ感度低下の説明日常の開発ニーズでは、データの感度低下が頻繁に発生します。たとえば、ID ...

キャンバス操作プラグイン fabric.js の使い方を詳しく解説

Fabric.js は非常に便利なキャンバス操作プラグインです。ここでは、日常のプロジェクトで使用さ...

MySQLトリガーの簡単な使用例

この記事では、例を使用して MySQL トリガーの簡単な使用方法を説明します。ご参考までに、詳細は以...

WebWorkerはJavaScriptサンドボックスの詳細をカプセル化します

目次1. シナリオ2. IJavaScriptShadowboxを実装する2.1 メインスレッドの実...

Tomcatサーバーのセキュリティ設定方法

Tomcat は、Java Community Process を通じて Sun が開発した、広く使...

角度コンテンツ投影の詳細な説明

目次単一コンテンツ投影マルチコンテンツ投影単一条件のコンテンツ投影アプリ-人物-htmlアプリ担当者...

CSS3 変換によって子要素の固定位置を絶対位置に変更する方法

この記事では、CSS3 の transform を使用して子要素の固定配置を絶対配置に変更する方法を...

JSは5つ星の賞賛効果を達成

JS を使用してオブジェクト指向メソッドを実装し、JD.com の 5 つ星レビュー効果を実現します...

MySQL ビュー管理ビューの例の詳細説明 [追加、削除、変更、クエリ操作]

この記事では、例を使用して MySQL ビューの管理ビュー操作について説明します。ご参考までに、詳細...

div が隠しテキストを超え、div 部分の向こうの CSS コードを隠します

隠れる前に:隠れた後: CS: ...コードをコピーコードは次のとおりです。オーバーフロー:非表示;...

Centos7 システムでの MySQL マスター スレーブ同期構成スキーム

序文最近、高可用性プロジェクトに取り組む際には、データの同期が必要になっています。ノードが 2 つし...

HTTP および HTTP コラボレーション Web サーバー アクセス フロー図

Web サーバーは、独立したドメイン名を持つ複数の Web サイトを構築できるほか、通信経路上のトラ...

Typescript での infer キーワードの使用に関する詳細な理解

目次推測する事例:理解を深める参照する後で忘れないように、キーワード infer をメモしておきます...

DockerにTensorFlow環境を素早くインストールする方法

Docker に TensorFlow 環境をすばやくインストールし、TensorFlow を使用し...

Vue 天気予報入門

この記事では、参考までに天気予報を実装するためのVueの具体的なコードを紹介します。具体的な内容は次...