litelementとtypescriptを用いたWebコンポーネントの統合


前の投稿ではhow to create a project based on LitElement and TypeScript スクラッチから.また、私はrouting management そして、ナビゲーションライフサイクルをより制御する方法を説明しました.
どのようにそれらを再利用するかを理解するためにWebコンポーネントの作成を深くダイビング、任意のプロパティの変更に応答し、カスタムイベントを派遣しましょう.

Webコンポーネントの作成


Webアプリケーション内のすべてのブログ記事の概要を表示するには、基本テンプレートを定義しましょう.
<div class="blog-card">
  <div class="blog-description">
    <h1>Title</h1>
    <h2>Author</h2>
    <p>
      Brief Description
    </p>
    <p class="blog-footer">
      <a class="blog-link">Read More</a>
    </p>
  </div>
</div>
このテンプレートを使用すると、ポストコンテンツを表示する単純なカードを描画することを期待してください.新しいコンポーネントの内部DOMを定義します.
Webコンポーネントを作成しましょうLitElement@customElement デコレータ
// blog-card.ts

import { LitElement, html, customElement, css } from 'lit-element';
import { Post } from './post';

@customElement('blog-card')
export class BlogCard extends LitElement {
  static styles = css`
  .blog-card {
    margin: 20px;
    display: flex;
    flex-direction: column;
    margin-bottom: 15px;
    background: white;
    border-radius: 5px;
    overflow: hidden;
    border-radius: 10px;
  }
  .blog-description {
    padding: 20px;
    background: white;
  }
  .blog-footer {
    text-align: right;
  }
  .blog-link {
    color: #008cba;
  }
  h1 {
    margin: 0;
    font-size: 1.5rem;
  }
  h2 {
    font-size: 1rem;
    font-weight: 300;
    color: #5e5e5e;
    margin-top: 5px;
  }
  `;

  render() {
    return html`
      <div class="blog-card">
        <div class="blog-description">
          <h1>Title</h1>
          <h2>Author</h2>
          <p>
            Brief Description
          </p>
          <p class="blog-footer">
            <a class="blog-link">Read More</a>
          </p>
        </div>
      </div>
    `;
  }
}
このコンポーネントはレンダリング可能です.しかし、内容が常に同じままであるので、それは再利用できません.このコンポーネントを構成するには、それぞれのインスタンスごとに異なるコンテンツを表示できるように設定する必要があります(これは理想的です.

プロパティの追加


要素のプロパティを宣言する型スクリプトの方法は次のとおりです.
// blog-card.ts

@customElement('blog-card')
export class BlogCard extends LitElement {

  @property({ type: String }) postTitle?: string;
  @property({ type: String }) author?: string;
  @property({ type: String }) description?: string;
}
それは、私たちの新しい構成要素を構成するのに十分に見えて、ブログ柱の概要を表示することができます.しかし、他の属性を追加する場合はどうなりますか?プロパティのリストは、数が増加し、おそらくこのシナリオを処理する最良の方法ではないでしょう.
他のオプションはPost 型スクリプトインターフェイスによるモデル
// post.ts
export interface Post {
  id: number;
  title: string;
  author: string;
  description: string;
}
次に、POSTオブジェクトを想定する単一のプロパティを定義します.
// blog-card.ts

@customElement('blog-card')
export class BlogCard extends LitElement {

  @property({ type: Object }) post?: Post;
}

結合プロパティー


改善する時だrender テンプレートにプロパティバインドを作成します.
// blog-card.ts

  render() {
    return html`
      <div class="blog-card">
        <div class="blog-description">
          <h1>${this.post?.title}</h1>
          <h2>${this.post?.author}</h2>
          <p>
            ${this.post?.description}
          </p>
          <p class="blog-footer">
            <a class="blog-link">Read More</a>
          </p>
        </div>
      </div>
    `;
  }
The @property 宣言(前に定義された)は、指定されたプロパティが変更されるたびにテンプレートをレンダリングします.

イベントの追加


Webコンポーネントのイベントリスナーを追加する方法は異なります.この場合、宣言イベントリスナーを使用します@event 記法
  render() {
    return html`
      <div class="blog-card">
        <div class="blog-description">
          <h1>${this.post?.title}</h1>
          <h2>${this.post?.author}</h2>
          <p>
            ${this.post?.description}
          </p>
          <p class="blog-footer">
            <a class="blog-link" @click="${this.handleClick}">Read More</a>
          </p>
        </div>
      </div>
    `;
  }

  private handleClick() {
    this.dispatchEvent(
      new CustomEvent('readMore', { detail: this.post })
    );
  }
イベントリスナー@click="${this.handleClick}" テンプレートがブラウザでレンダリングされると、追加されます.クリックアクションは、handleClick 関数.
この関数は、我々の点灯ベースのWebコンポーネントからイベントを発生させます.The CustomEvent オブジェクトを許可するPost それとともに伝播する.

親子コンポーネント通信


The blog-card コンポーネントは、アプリケーションに統合する準備が整いました.

親ページとブログカードを子コンポーネントとしてブログ投稿ページで考えてみましょう.
// blog-posts.ts

import { POSTS } from './data';
import { Post } from './post';

@customElement('lit-blog-posts')
export class BlogPosts extends LitElement {

  @property({ type: Array }) blogPosts?: Post[];

  constructor() {
    super();
  }

  render() {
    return html`
      <h2>Blog Posts</h2>
      ${this.blogPosts?.map(
        post => html`<blog-card .post="${post}"></blog-card>`
      )}
    `;
  }

  firstUpdated() {
    this.blogPosts = POSTS;
  }
}
親コンポーネントは、ブログ投稿の集合を格納するプロパティを定義します@property({ type: Array }) blogPosts?: Post[]; .
Webコンポーネントテンプレートを持ち、プロパティーをバインドする場合は、次の規則を考慮します
  • テキスト内容:<p>${...}</p>
  • 属性<p id="${...}"></p>
  • boolean属性:?disabled="${...}"
  • プロパティー.value="${...}"
  • イベントハンドラ@event="${...}"
  • The firstUpdated 関数は、要素のDOMが初めて更新された後に呼び出されます.現実世界のシナリオでは、アプリケーションは、データを取得するためにHTTPコールを実行する必要があります.
    この例では、データを読み込みますdata.ts ファイル
    // data.ts
    
    import { Post } from './post';
    
    export const POSTS: Post[] = [
      {
        id: 0,
        title: 'Web Components Introduction',
        author: 'Luis Aviles',
        description:
          'Lorem ipsum dolor sit amet, consectetur adipiscing elit...',
      },
      {
        id: 1,
        title: 'LitElement with TypeScript',
        author: 'Luis Aviles',
        description:
          'Sed felis nisi, consectetur sed ipsum dignissim, semper porta risus...',
      },
      {
        id: 2,
        title: 'Navigation and Routing with Web Components',
        author: 'Luis Aviles',
        description:
          'Ut ipsum arcu, sodales aliquet nisi iaculis, faucibus varius mauris...',
      },
    ];
    

    子供イベント


    親コンポーネントはブログ記事を表示する準備ができています.しかし、「もっと読む」リンクがクリックされて、ブログ投稿ページからコントロールを取るたびに、聞くのは素晴らしいです:
    // blog-posts.ts
    
      firstUpdated() {
        this.blogPosts = POSTS;
        this.addEventListener('readMore', event => {
          const post = (event as CustomEvent).detail as Post; //event.detail has a the Post object
          Router.go(`/blog/posts/${post.id}`); // Get the Post id and redirect
        });
      }
    
    イベントリスナーは最初のペイントの後に実行されます.これらの追加方法は、いくつかのリスナーを追加するときに便利です.
    これは最終結果です.

    ソースコードプロジェクト


    このGithubリポジトリ内の完全プロジェクトを見つけます.https://github.com/luixaviles/litelement-website . それは星を与えることを忘れないでください⭐️ そして、コードで遊んでください.
    あなたは私に従うことができますGitHub 私の仕事についてもっと見る.