LoginSignup
14
11

More than 5 years have passed since last update.

LitElement + TypeScript でTodoリスト

Last updated at Posted at 2018-11-13

lit-capture

前回lit-htmlを勉強したので、LitElementについて勉強します。 Polymerとはいろいろ変ったらしく、TypeScriptで作られていますね、、、

my-element.js
import {LitElement, html} from '@polymer/lit-element'

class MyElement extends LitElement {

  static get properties() {
    return {
      name: { type: String }
    }
  }

  constructor(){
    super()
    this.name = 'World'
  }

  render() {
    return html`
      <h1>Hello ${this.name} !</h1>
      <input @input=${ e => this.name=e.target.value }>
    `
  }

}
customElements.define('my-element', MyElement)

こんな感じで書いたHello World !(23行)が、

my-element.ts
import {LitElement, customElement, property, html} from '@polymer/lit-element'

@customElement('my-element') class extends LitElement {

  @property() name = 'World'

  render(){
    return html`
      <h1>Hello ${this.name} !</h1>
      <input .value=${this.name} @input=${ e => this.name=e.target.value }>
    `
  }

}

:globe_with_meridians: デモサイト (stackblitz)

これぐらい(14行)で書けるならTypeScriptもよいのかも

※ 厳密には@customElementデコレータではHTMLElementTagNameMapインタフェースを定義する必要があるらしい

LitElementとは

  • サイズが小さく高速
  • 主としてHTML属性(attribute)やDOMプロパティ(property)の操作を便利にしてくれるHTML要素の拡張ライブラリ
  • 描画はlit-htmlによって非同期に処理されるので、関数的に作らなくてはいけない

内部的なライフサイクル

基本、プロパティを操作(例: this.foo = 'a')してlit-htmlに渡せばよいのですが、細かく制御するには下記(Element update lifecycle)の遷移を把握しておく必要があります( await this.updateComplete とかよく使うぽい )。

At a high level, the update lifecycle is:

1. A property is set.
2. The property’s hasChanged function evaluates whether the property has changed.
3. If the property has changed, requestUpdate fires, scheduling an update.
4. shouldUpdate checks whether the update should proceed.
5. If the update should proceed, the update function reflects the element’s properties to its attributes.
6. The lit-html render function renders DOM changes.
7. The updated function is called, exposing the properties that changed.
8. The updateComplete Promise resolves. Any code waiting for it can now run.

更新のライフサイクルについて(意訳):

  1. プロパティが設定されると、
  2. プロパティ毎に設定 される hasChanged(newValue, oldValue)によって プロパティが変更されたかどうか を確認。
  3. プロパティが変更されたならrequestUpdate()を呼んで描画をスケジューリングし、
  4. shouldUpdate(changedProperties) によって描画をすべきか確認。
  5. 描画してよいならupdate(changedProperties)が呼ばれて各属性やプロパティを更新し、
  6. (やっと) lit-htmlがDOMに描画。
  7. (※追加 最初の描画時はfirstUpdated(changedProperties)呼ばれつつ) update(changedProperties)が呼ばれ、プロパティも更新済みとなり、
  8. updateCompleteがresolveされる

Todoリスト

awesome-lit-htmlに載っていた、LitElementとvueReactの実装を比較した素敵な記事があったので、これをTSで短く書き換えてみます。

todo-list.ts
import {LitElement, html, property, customElement} from '@polymer/lit-element'

@customElement('todo-item') default class extends LitElement {

  @property() todo=''

  @property({type: Function}) remove

  render() {
    return html`${this.todo} <button @click=${this.remove}>-</button>`
  }

}

@customElement('todo-list') default class extends LitElement {

  @property() list = ['clean the house','buy milk']

  @property() todo = ''

  newTodo(){
    this.list = [...this.list, this.todo]
    this.todo=''
  }

  render() {
    return html`
      <h2>ToDo List</h2>
      <ul>
        ${this.list.map( (v, index) => html`<li>
           <todo-item
             .todo=${v}
             .remove=${() => this.list = this.list.filter((_,i)=> index !== i)}></todo-item>
         </li>`)}
      </ul>
      <input
        .value=${this.todo}
        @input=${e=>this.todo = e.target.value}
        @keypress=${e=> e.target.value !== '' && e.key === 'Enter' && this.newTodo()}>
      <button @click=${e=>this.todo !== '' && this.newTodo()}>+</button>
      `
  }
}

:globe_with_meridians: デモサイト (stackblitz)

親要素(todo-list)でToDoの各アイテムを削除する関数をつくって、

todo-list
<todo-item .remove=${() => this.list = this.list.filter((_,i)=> index !== i)}>

子要素(todo-item)でプロパティとして受けとるのが新鮮でした(他フレームワークでは一般的なのかな、、、)

todo-item
@property({type: Function}) remove

(未解決課題: IE11でエラー。CSSの適用)

サンプルのWebアプリでは別途Reduxなどで状態管理をして、pwa-helperを使ってPWAにしてるので、次回また勉強してみます。

(続き :arrow_right: LitElement+Reduxでカウンター)

14
11
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
14
11