LitElement 및 TypeScript를 사용한 웹 구성 요소 통합

9197 단어 litelementtypescript
이전 게시물에서 처음부터 how to create a project based on LitElement and TypeScript 설명했습니다. 또한 routing management을 추가하고 탐색 수명 주기를 더 잘 제어하는 ​​방법을 설명했습니다.

웹 구성 요소 생성에 대해 자세히 살펴보고 이를 재사용하고 속성 변경에 응답하고 사용자 지정 이벤트를 전달하는 방법을 이해하겠습니다.

웹 구성 요소 작성



웹 애플리케이션의 모든 블로그 게시물에 대한 개요를 표시하는 기본 템플릿을 정의해 보겠습니다.

<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을 정의합니다.

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>
    `;
  }
}

이 구성 요소는 렌더링할 준비가 되었습니다. 그러나 내용은 항상 동일하므로 재사용할 수 없습니다. 각 인스턴스에 대해 다른 콘텐츠를 표시할 수 있도록 이 구성 요소를 구성하는 방법이 필요합니다(이상적이어야 합니다. 맞습니까?).

속성 추가



요소의 속성을 선언하는 TypeScript 방식은 다음과 같습니다.

// 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;
}

새 구성 요소를 구성하고 블로그 게시물의 개요를 표시할 수 있을 것 같습니다. 그러나 다른 속성을 추가하기로 결정하면 어떻게 될까요? 속성 목록의 수가 증가할 것이며 이 시나리오를 처리하는 최선의 방법이 아닐 수도 있습니다.

다른 옵션은 TypeScript 인터페이스를 통해 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>
    `;
  }
@property 선언(이전에 정의됨)은 지정된 속성이 변경될 때마다 템플릿을 렌더링합니다.

이벤트 추가



웹 구성 요소에 대한 이벤트 리스너를 추가하는 방법에는 여러 가지가 있습니다. 이 경우 @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 함수에 의해 처리됩니다.

이 함수는 Lit 기반 웹 구성요소에서 이벤트를 발생시킵니다. CustomEvent를 사용하면 개체Post가 함께 전파될 수 있습니다.

부모-자식 구성 요소 통신


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[]; 를 사용하여 블로그 게시물 세트를 저장하는 속성을 정의합니다.

웹 구성 요소 템플릿이 있고 속성을 바인딩하려는 경우 다음 규칙을 고려하십시오.
  • 텍스트 콘텐츠: <p>${...}</p>
  • 속성: <p id="${...}"></p>
  • 부울 속성: ?disabled="${...}"
  • 속성: .value="${...}"
  • 이벤트 핸들러: @event="${...}"

  • 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에서 나를 팔로우할 수 있습니다.

    좋은 웹페이지 즐겨찾기