Webコンポーネントによる製品カードコンポーネント


Webコンポーネント


Webコンポーネントを利用した製品カードコンポーネントを作成します.カスタムUIコントロールを作成するとき、Webコンポーネントは複合HTMLコードをカプセル化します.それは、コード衝突の恐れなしでどこでも再利用されることができるカスタム要素をつくるために、3つのテクノロジー(HTML、CSSとJavaScript)を利用します.

基礎


最初にWebコンポーネントを開始するカスタム要素を作成する必要があります.そのためには、要素の機能を指定するクラスや関数を作成します.HtmlElementクラスを拡張するProductCardComponentクラスというクラスを作成します.
class ProductCardComponent extends HTMLElement{
    constructor(){
        super();
    }
}
...
カスタム要素を登録するには、CustomElementRegistryを使用します.define ()メソッド.このメソッドは2つの引数と1つのオプションをとります.最初の引数は、カスタム要素の名前としてハイフン分離文字列(kebabケース)を取ります.私達は私達の要素プロダクトカードを命名する.番目の引数は、要素の動作を定義するクラスまたは関数の名前です.
...
window.customElements.define('product-card', ProductCardComponent);

影のドーム


Webコンポーネントのカプセル化の主要部分の一つはシャドウDOMです.シャドウDOMは、コンポーネントのスタイル、構造、および動作がページ上の他のコードのいずれかと衝突しないようにするために、隠された分離DOMを要素にアタッチする方法を提供します.
シャドウDOMをカスタム要素にアタッチするには、要素を使用します.コンストラクタでのAttachShadow ()メソッド.これは1つの引数、およびキーを持つオブジェクト:モードと値:';開く';または';閉じ';.オープンは、メインページコンテキストで書かれたJavaScriptでシャドウDOMにアクセスできます.
...
constructor(){
   super();
   this.attachShadow({mode: 'open'});
}
...
次に、コンポーネントの構造を含む要素を作成します.そして、その要素をシャドウDOMに付ける.
...
constructor(){
   super();
   this.template = document.createElement('template');
   this.template.innerHTML = ` `;

   this.attachShadow({mode: 'open'});
   this.shadowRoot.appendChild(this.template.content.cloneNode(true));
}
...
これはセットアップのためです、そして、現在、我々は我々の構成を開始することができます.

製品カードコンポーネント



製品カードは、それが表示される製品のイメージを表示します.このイメージのソースを設定するには、コンポーネントのユーザーを許可する必要があります.また、メインテキスト領域(製品名が表示されます)は、サブテキスト領域(これは、製品の価格が表示されます)、そのテキスト、テキストの色、および背景色を設定するユーザーが設定できるようになりますボタン.これらの要素のそれぞれについて、値を設定し、ボタンの名前を設定するためにinnerhtmlを使用します.
<product-card img='./source.jpg' 
   main='Product Name' 
   sub-one='$10.00'
   button-color='orange'
   button-text-color='black'> Button Text </product-card>
次に、コンストラクタで変数を作成し、属性の値に設定します.
...
constructor(){
   super();
   this.template = document.createElement('template');

   this.main = this.getAttribute('main');
   this.img = this.getAttribute('img');
   this.subOne = this.getAttribute('sub-one');
   this.buttonColor = this.getAttribute('button-color');
   this.buttonTextColor = this.getAttribute('button-text-color');
   this.buttonText = this.innerHTML;

   this.template.innerHTML = ` 

   `;

   this.attachShadow({mode: 'open'});
   this.shadowRoot.appendChild(this.template.content.cloneNode(true));
}
...
次に、コードを文字列で記述し、テンプレートに割り当てることでコンポーネントを構築します.innerhtml.私たちのコンポーネントは2つのメインブロックから成ります.したがって、これらのブロックを表現するために2つのDIVSを作成して、コンテナ部でそれらをラップします.コンテナdivにカードcontのクラス名とimg - contとinfo - contyの2つの包まれたdivクラス名を与えます.以前に作成した変数を使用して、img要素のsrc属性とメインテキスト、副テキスト、およびボタンテキストのテキストを入力します
...
   this.template.innerHTML = `
   <div class='card-cont'>
      <div class='img-cont'>
         <img src='${this.img}' alt='${this.main}'/>
      </div>
      <div class='info-cont'>
         <div class='top-info-cont'>
            <div class='main-cont'><p>${this.main}<p></div>
            <div class='sub1-cont'><p>${this.subOne}<p></div>
         </div>
         <div class='bottom-button-cont'>
            <button>${this.buttonText}</button>
         </div>
      </div>
   </div>
`
...
スタイルを設定するには、コンポーネントをカードcont部の右側に追加します.
...
   this.template.innerHTML =`
   <style>
   </style>
   <div class='card-cont'>
      ...
   </div>
`
...

ボタンとコンテナスタイル
...
this.template.innerHTML= `
      <style>
         button{
             min-width: 7rem;
             height: 1.8rem;
             opacity: 0;
             transition: 100ms ease 0s;
             border-radius: .5rem;
             border: none;
             background-color: ${this.buttonColor} ;
             font-weight: 300;
             font-size: .7rem;
             color: ${this.buttonTextColor};
         }
         img{
             width: 100%;
             min-height: 100%;
         }
         .card-cont{
             font-family: Segoe UI, sans-serif;
             font-size: .98rem;
             position: relative;
             background-color: none;
             width: 16.3rem;
             height: 16rem;
             transition: 500ms;
             color: white;
         }
         .img-cont{
             background-color: grey;
             width: 15rem;
             height: 15rem;
             transition: 500ms;
             overflow: hidden;
         }
         .info-cont{
             position: absolute;
             background-color: black;
             width: 11.8rem;
             height: 1.2rem;
             top: 13.75rem;
             left: 2.5rem;
             border-radius: .6rem;
             transition: height 500ms;
             padding: .5rem 1rem;
             box-shadow: 0px 0px 8px rgba(1,1,1,.3);
         }
         .top-info-cont{
             display: flex;
             justify-content: center;
             min-height: 50%;
             width: 100%;
         }
         .bottom-button-cont{
             display: flex;
             justify-content: center;
             align-items: center;
             height: 50%;
             width: 100%;
         }
         .main-cont{
             display: flex;
             flex-wrap: nowrap;
             font-weight: 700;
             text-align: left;
             width: 70%;

         }
         .sub1-cont{
             font-size: .8rem;
             text-align: right;
             width: 30%;

         }
      ...
      </style>
...
`

アニメーションとインタラクションスタイル
...
this.template.innerHTML =`
         ...
            .card-cont:hover{
                transform: scale(1.05,1.05);
                z-index: 100;
            }
            .card-cont:hover > .img-cont{
                border-radius: 1rem;
                box-shadow: 30px 30px 50px rgba(1,1,1,.3);
            }
            .card-cont:hover > .info-cont{
                height: 5.5rem;
                box-shadow: 30px 30px 50px rgba(1,1,1,.3);
            }
            .card-cont:hover top-info-cont{
                height: 50%;
            }
            .card-cont:hover button{
                opacity: 1;
                transition: 500ms ease-in 0s;
            }
            button:active{
                transform: scale(1.1,1.1);
            }
            .card-cont:focus{
                outline: 1px solid black;
                outline-offset: .5rem;
            }
         ...
`
...
これでカードコンポーネントが完成します.

エキストラ


ここでは、まだ我々がまだ話していない他のウェブ構成要素機能を使っている我々の構成要素にすることができるいくつかの異なる変更があります.

カスタムイベント


Webコンポーネント内のボタンがクリックされたときにコンポーネントのユーザーが知っているようにするには、ユーザーがイベントリスナーを実行できるカスタムイベントを作成できます.開始するには、要素クラスでメソッドを作成し、ボタンをクリックします.このメソッドの内部では、CustomEvent ()コンストラクターで新しいカスタムイベントを作成し、それをイベントという名前のconstに割り当てます.カスタムイベントは2つの引数をとります.最初に、イベントの名前を表す文字列と、任意の値のキー'詳細'を持つ2番目のオブジェクトです.詳細は、イベントリスナーに渡される任意のデータを含めることができます.次に、メソッドにイベントをディスパッチします.
...
   buttonClicked(){
      const event = new CustomEvent('',{
         detail:{
            id:this.id
         }
      });
      document.dispatchEvent(event);
   }
...

Webコンポーネント: ConnectedCallbackとdisconnectedCallback


カスタム要素が最初にドキュメントDOMに接続されているときにConnectedCallbackが呼び出されます.disdom tedcallbackはDOMから切断する際に呼び出されます.ConnectedCallbackメソッドを使用して、コンポーネントボタンの「Click」のイベントリスナーを実行し、そのイベントリスナーを削除するにはDisconnectedCallbackを使用します.
...
connectedCallback() {
   this.shadowRoot.querySelector('button').addEventListener('click', () => this.buttonClicked());
   }
disconnectedCallback() {
   this.shadowRoot.querySelector('button').removeEventListener();
   }
...

Webコンポーネント:スロット


スロット要素は、自分のマークアップで埋めることができる場所の所有者です.それはあなたが別々のDOMツリーを作成し、一緒に提示することができます.我々は、我々の一番下のボタン容器divのボタンを取り除き、スロット要素でそれを取り替えます.それから、私たちは要素をinnerhtmlにスロット要素に挿入します.これにより、Webコンポーネントのユーザーがコンポーネントの情報cont領域に独自のマークアップを置くことができます.
this.main = this.getAttribute('main');
   this.img = this.getAttribute('img');
   this.subOne = this.getAttribute('sub-one');
   this.buttonColor = this.getAttribute('button-color');
   this.buttonTextColor = this.getAttribute('button-text-color');
   this.userMrkUp = this.innerHTML;

   this.template.innerHTML = `
...
   <div class='card-cont'>
      <div class='img-cont'>
         <img src='${this.img}' alt='${this.main}'/>
      </div>
      <div class='info-cont'>
         <div class='top-info-cont'>
            <div class='main-cont'><p>${this.main}<p></div>
            <div class='sub1-cont'><p>${this.subOne}<p></div>
         </div>
         <div class='bottom-button-cont'>
            <slot>${this.userMrkUp}</slot>
         </div>
      </div>
   </div>
`
...
Code