0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

LitElementのDOM変化でView Transitions APIを使って簡単かつ綺麗な凡庸アニメーションを実装する方法

Last updated at Posted at 2023-09-08

ハイサイ!オースティンやいびーん!

概要

ChromeとEdgeがサポートしているView Transitions APIをLitと一緒に使うと、とても簡単に再レンダー時のスムーズなアニメーションができます。

アニメーションを付ける部品

ChromiumベースのブラウザでLitの砂場を開きましょう。

この単純なデフォルトの部品にステート変更を加えて、再レンダーを起こすようにします。

import {html, css, LitElement} from 'lit';
import {customElement, property} from 'lit/decorators.js';

@customElement('simple-greeting')
export class SimpleGreeting extends LitElement {
  static styles = css`p { color: blue }`;

  @property()
  name = 'World';
  
  firstUpdated() {
    setInterval(() => {
      const newName = this.name === 'World' ? 'Lit' : 'World';
      this.name = newName;
    }, 2000);
  }

  render() {
    return html`<p>Hello, ${this.name}!</p>`;
  }
}

firstUpdatedはLitが最初にDOMにレンダーした後に呼ばれるメソッドです。その時に2秒おきにnameを変えるようにします。

結果

ezgif.com-video-to-gif.gif

急に変わるようになっています。これをスムーズに変わるようにしましょう。

View Transitions APIをLitのレンダー時に作動させる

Litのソースコードを調べてみると、LitElementが実際にDOMの変更を行なってくれる'lit-html.renderを呼んでくれるのは、update`というメソッドの中です。

  /**
   * Updates the element. This method reflects property values to attributes
   * and calls `render` to render DOM via lit-html. Setting properties inside
   * this method will *not* trigger another update.
   * @param changedProperties Map of changed properties with old values
   * @category updates
   */
  protected override update(changedProperties: PropertyValues) {
    // Setting properties in `render` should not trigger an update. Since
    // updates are allowed after super.update, it's important to call `render`
    // before that.
    const value = this.render();
    if (!this.hasUpdated) {
      this.renderOptions.isConnected = this.isConnected;
    }
    super.update(changedProperties);
    this.__childPart = render(value, this.renderRoot, this.renderOptions);
  }

これを自分らの部品で動作を変えたらView Transitions APIを再レンダーのたびに引き起こせそうです。

updateをoverrideする

updateをoverrideして、元の関数を呼ぶようにしましょう。

import {html, css, LitElement, PropertyValues} from 'lit';
import {customElement, property} from 'lit/decorators.js';

@customElement('simple-greeting')
export class SimpleGreeting extends LitElement {
  static styles = css`p { color: blue }`;

  @property()
  name = 'World';
  
  firstUpdated() {
    setInterval(() => {
      const newName = this.name === 'World' ? 'Lit' : 'World';
      this.name = newName;
    }, 2000);
  }
  
  render() {
    return html`<p>Hello, ${this.name}!</p>`;
  }
  
  override update(changed: PropertyValues) {
    const update = super.update.bind(this, changed);
    
    if (!('startViewTransition' in document)) {
      update();
      return;
    }

    // TypeScriptはまだstartViewTransitionを知らないようです
    (document as any).startViewTransition(update);
  }
}

override updateでは、呼びたい関数をupdateという中間変数にbindを使ってまとめ、View Transitions APIがサポートされていれば、作動するように呼んでいます。

サポートされていなければ、従来通り呼ぶだけで終わりです。

結果

ezgif.com-video-to-gif (1).gif

Gifなのでちょっと荒いかもしれませんが、とても滑らかにアニメートされています!

これでモーダルのアニメーションをほぼ何もせずに、CSSに触れずにできてしまいます!:innocent:

まとめ

簡単に紹介しましたが、実に様々なアニメーション、それこそネットフリックスのようなアニメーションをとても簡単に実装できるようになったのです。

ブラウザのAPIなので、パフォーマンスもよく、バグも起きないのです。

このView Transition APIについて知りたければ、Chromeの記事をぜひお読みください。

Litじゃなくても使えます!

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?