入門から放棄へ:Web Components


Web Componentsを検索しているのは誰ですか?
Web Componentsを検索するのは通常、Web Componentsを使用しないので、あなたと私のように、暇で勉強が好きで、あるいはフロントエンドの面接に対処しなければならないので、理解しなければなりません.
Web Componentsを使用しないのは多くの客観的な原因があります.例えば、あなたとWeb Componentsの間には約nつのフロントエンドフレームワークがあります.これらのフレームワークは面接の仕事に必要です.それらの大規模なアプリケーションに基づく実戦だけでなく、ソースコードの原理を理解する能力もあります.
だからWeb Componentsは自然にあなたのショートボードの一つになります.
なぜWeb Components
個人的にはここ数年の先端はずっと1つの問題をめぐっていると思います:コンポーネント化、例えば先端三国演義(React,Vue,Angular)の発展とその熱さは十分に説明していますが、1つの問題はずっと解決していません.それはコンポーネントの多重化の問題で、はっきり言ってどのように繰り返し車輪の問題を防止するかです.私はこれが問題だとは思いませんが、W 3 Cはこれが問題だと思っています.Web Componentsを勉強しなければなりません
W 3 Cの解決策は、仕様と基準を制定することによって、すべてのブラウザに一連のプラットフォームAPIを提供してカスタムHTMLラベルをサポートすることであり、これらのAPIに基づいて作成されたコンポーネントがすべてのサポートされているブラウザで実行され、コンポーネントの多重化を達成することができる.
Web Componentsの内容
W 3 Cやネット上の他の言論に洗脳されると、Web Componentsが未来だと信じ、どんな三国演義もそろっているので、Web Componentsをどのように書くかを知る必要があります.
まずWeb Componentsは4つの規範に基づいています:カスタム要素、影DOM、ESモジュール、HTMLテンプレート、私はあなたにやはり入らないことをお勧めします.規範は怠け者のおばあさんの足のように、臭いし、長いので、簡単なhello worldやtodoが必要です.
hello-world.js
const template = document.createElement('template');

template.innerHTML = `
  
  

Hello: World

`; class HelloWorld extends HTMLElement { constructor() { super(); this._shadowRoot = this.attachShadow({ mode: 'open' }); this._shadowRoot.appendChild(template.content.cloneNode(true)); this.$headline = this._shadowRoot.querySelector('h2'); this.$span = this._shadowRoot.querySelector('span'); } connectedCallback() { if(!this.hasAttribute('color')) { this.setAttribute('color', 'orange'); } if(!this.hasAttribute('text')) { this.setAttribute('text', ''); } this._render(); } static get observedAttributes() { return ['color', 'text']; } attributeChangedCallback(name, oldVal, newVal) { switch(name) { case 'color': this._color = newVal; break; case 'text': this._text = newVal; break; }; this._render(); } _render() { this.$headline.style.color = this._color; this.$span.innerHTML = this._text; } } window.customElements.define('hello-world', HelloWorld);

hello-world.html


  
    Hello World Web Components
  
  
    
    
  

コンポーネントを くのは なことがわかりますが、 は あなたの の にはWeb Componentsの があります. に、 のコードと する と を します.
1.カスタム :
class HelloWorld extends HTMLElement {...}

HTML Elementクラスを するだけで、カスタムラベル/ を できます.コンストラクション とライフサイクル は に されません.
2.HTMLテンプレート
const template = document.createElement('template');
template.innerHTML = ...

HTMLタグには なスタイルとDOM、 DOMが まれています
this._shadowRoot = this.attachShadow({ mode: 'open' });
this._shadowRoot.appendChild(template.content.cloneNode(true));

HelloWorldクラスとテンプレートは も がなく、 DOMの の はHelloWorldクラスとテンプレートを し、サブDOMツリーとして することです. に DOMは、スタイルが されたり れたりしないことを し、モジュール されたパッケージを する.
3.グローバル コンポーネント
window.customElements.define('hello-world', HelloWorld);

コンポーネント 、このjsファイルを することで、このWeb Componentsを することができます.
これで、 なWeb Componentsを するプロセスは、ほぼ できましたが、 で なプロジェクトに するには、より くのAPIサポートが です.
コンポーネントライフサイクル
class MyElement extends HTMLElement {
    constructor() {
        // always call super() first
        super(); 
        console.log('constructed!');
    }

    connectedCallback() {
        console.log('connected!');
    }

    disconnectedCallback() {
        console.log('disconnected!');
    }

    attributeChangedCallback(name, oldVal, newVal) {
        console.log(`Attribute: ${name} changed!`);
    }

    adoptedCallback() {
        console.log('adopted!');
    }
}

1. constructor()
は されたがdocumentに されていない に され、 はステータスの 、イベントリスニング、シャドウDOMの に されます.
2. connectedCallback()
がDOMに されると され、 はデータを し、デフォルトのプロパティを するために されます.
3. disconnectedCallback()
がDOMから されると され、 はイベントのリスニングやタイマのキャンセルなどのクリーンアップ に されます.
4. attributeChangedCallback(name, oldValue, newValue)
が する の は されますが、 の を するとしますか?
static get observedAttributes() {
    return ['my-attr'];
}

my-attr が するとattributeChangedCallbackがトリガーされます
5. adoptedCallback()
カスタム が しいdocumentに されたときに されます.
Web Componentsに するほとんどの を っていますが、 し なTODOアプリケーションを る を てみましょう.
TODO
を に います.カスタムコンポーネントを2つ とします.
  • to-do-app
  • として を け れ、to-doを / /タグできます.
  • to-to-item
  • 、インデックス 、checked の
    to-do-app.js
    const template = document.createElement("template");
    template.innerHTML = `
    
    

    To do App

      `; class TodoApp extends HTMLElement { constructor() { super(); this._shadowRoot = this.attachShadow({ mode: "open" }); this._shadowRoot.appendChild(template.content.cloneNode(true)); this.$todoList = this._shadowRoot.querySelector("ul"); thisl.todos = []; } } window.customElements.define("to-do-app", TodoApp);

    setterとgetterの により、 しいプロパティを します.
    set todos(value) {
      this._todos = value;
      this._renderTodoList();
    }
    
    get todos() {
      return this._todos;
    }

    このアトリビュート に すと、to-doリストがレンダリングされます.
    _renderTodoList() {
        this.$todoList.innerHTML = "";
    
        this._todos.forEach((todo, index) => {
          let $todoItem = document.createElement("div");
          $todoItem.innerHTML = todo.text;
          this.$todoList.appendChild($todoItem);
        });
      }

    ボックスとボタンにイベントを する があります.
    constructor() {
        super();
        ...
        this.$input = this._shadowRoot.querySelector("input");
        this.$submitButton = this._shadowRoot.querySelector("button");
        this.$submitButton.addEventListener("click", this._addTodo.bind(this));
      }

    TOODを :
    _addTodo() {
            if(this.$input.value.length > 0){
                this._todos.push({ text: this.$input.value, checked: false })
                this._renderTodoList();
                this.$input.value = '';
            }
        }

    TODOアプリでtodoを できるようになりました.
    とタグを するには、to-do-itemを する があります.js
    to-do-item.js
    const template = document.createElement('template');
    template.innerHTML = `
    
    
  • `; class TodoItem extends HTMLElement { constructor() { super(); this._shadowRoot = this.attachShadow({ 'mode': 'open' }); this._shadowRoot.appendChild(template.content.cloneNode(true)); this.$item = this._shadowRoot.querySelector('.item'); this.$removeButton = this._shadowRoot.querySelector('button'); this.$text = this._shadowRoot.querySelector('label'); this.$checkbox = this._shadowRoot.querySelector('input'); this.$removeButton.addEventListener('click', (e) => { this.dispatchEvent(new CustomEvent('onRemove', { detail: this.index })); }); this.$checkbox.addEventListener('click', (e) => { this.dispatchEvent(new CustomEvent('onToggle', { detail: this.index })); }); } connectedCallback() { // We set a default attribute here; if our end user hasn't provided one, // our element will display a "placeholder" text instead. if(!this.hasAttribute('text')) { this.setAttribute('text', 'placeholder'); } this._renderTodoItem(); } _renderTodoItem() { if (this.hasAttribute('checked')) { this.$item.classList.add('completed'); this.$checkbox.setAttribute('checked', ''); } else { this.$item.classList.remove('completed'); this.$checkbox.removeAttribute('checked'); } this.$text.innerHTML = this._text; } static get observedAttributes() { return ['text']; } attributeChangedCallback(name, oldValue, newValue) { this._text = newValue; } } window.customElements.define('to-do-item', TodoItem);

    で、renderTodolistではto-do-itemをレンダリングし め、 する にimportを とすると、これは たちが に ったESモジュールの です.
    _renderTodoList() {
                this.$todoList.innerHTML = '';
    
                this._todos.forEach((todo, index) => {
                    let $todoItem = document.createElement('to-do-item');
                    $todoItem.setAttribute('text', todo.text);
                    this.$todoList.appendChild($todoItem);
                });
            }

    コンポーネントは、イベントによって コンポーネントに されます( ボタンとチェックボックス):
    this.$removeButton.addEventListener('click', (e) => {
                this.dispatchEvent(new CustomEvent('onRemove', { detail: this.index }));
            });
    
    this.$checkbox.addEventListener('click', (e) => {
                this.dispatchEvent(new CustomEvent('onToggle', { detail: this.index }));
            });
        });

    コンポーネントのリスニング:
    $todoItem.addEventListener('onRemove', this._removeTodo.bind(this));
    $todoItem.addEventListener('onToggle', this._toggleTodo.bind(this));

    コンポーネントのリスニング の :
    static get observedAttributes() {
        return ["text", "checked", "index"];
      }
    attributeChangedCallback(name, oldValue, newValue) {
        switch (name) {
          case "text":
            this._text = newValue;
            break;
          case "checked":
            this._checked = this.hasAttribute("checked");
            break;
          case "index":
            this._index = parseInt(newValue);
            break;
        }
      }

    ではtodo appの が しました
    to-do-app.js
    import "./components/to-do-item";
    const template = document.createElement("template");
    template.innerHTML = `
        
        

    Raw web components


    To do

      `; class TodoApp extends HTMLElement { constructor() { super(); this._shadowRoot = this.attachShadow({ mode: "open" }); this._shadowRoot.appendChild(template.content.cloneNode(true)); this.$todoList = this._shadowRoot.querySelector("ul"); this.$input = this._shadowRoot.querySelector("input"); this.todos = []; this.$submitButton = this._shadowRoot.querySelector("button"); this.$submitButton.addEventListener("click", this._addTodo.bind(this)); } _removeTodo(e) { this._todos.splice(e.detail, 1); this._renderTodoList(); } _toggleTodo(e) { const todo = this._todos[e.detail]; this._todos[e.detail] = Object.assign({}, todo, { checked: !todo.checked }); this._renderTodoList(); } _addTodo() { if (this.$input.value.length > 0) { this._todos.push({ text: this.$input.value, checked: false }); this._renderTodoList(); this.$input.value = ""; } } _renderTodoList() { this.$todoList.innerHTML = ""; this._todos.forEach((todo, index) => { let $todoItem = document.createElement("to-do-item"); $todoItem.setAttribute("text", todo.text); if (todo.checked) { $todoItem.setAttribute("checked", ""); } $todoItem.setAttribute("index", index); $todoItem.addEventListener("onRemove", this._removeTodo.bind(this)); $todoItem.addEventListener("onToggle", this._toggleTodo.bind(this)); this.$todoList.appendChild($todoItem); }); } set todos(value) { this._todos = value; this._renderTodoList(); } get todos() { return this._todos; } } window.customElements.define("to-do-app", TodoApp);

    to-do-item.js
    const template = document.createElement("template");
    template.innerHTML = `
        
        
  • `; class TodoItem extends HTMLElement { constructor() { super(); this._shadowRoot = this.attachShadow({ mode: "open" }); this._shadowRoot.appendChild(template.content.cloneNode(true)); this.$item = this._shadowRoot.querySelector(".item"); this.$removeButton = this._shadowRoot.querySelector("button"); this.$text = this._shadowRoot.querySelector("label"); this.$checkbox = this._shadowRoot.querySelector("input"); this.$removeButton.addEventListener("click", e => { this.dispatchEvent(new CustomEvent("onRemove", { detail: this.index })); }); this.$checkbox.addEventListener("click", e => { this.dispatchEvent(new CustomEvent("onToggle", { detail: this.index })); }); } connectedCallback() { if (!this.hasAttribute("text")) { this.setAttribute("text", "placeholder"); } this._renderTodoItem(); } static get observedAttributes() { return ["text", "checked", "index"]; } attributeChangedCallback(name, oldValue, newValue) { switch (name) { case "text": this._text = newValue; break; case "checked": this._checked = this.hasAttribute("checked"); break; case "index": this._index = parseInt(newValue); break; } } _renderTodoItem() { if (this.hasAttribute("checked")) { this.$item.classList.add("completed"); this.$checkbox.setAttribute("checked", ""); } else { this.$item.classList.remove("completed"); this.$checkbox.removeAttribute("checked"); } this.$text.innerHTML = this._text; } set index(val) { this.setAttribute("index", val); } get index() { return this._index; } get checked() { return this.hasAttribute("checked"); } set checked(val) { if (val) { this.setAttribute("checked", ""); } else { this.removeAttribute("checked"); } } } window.customElements.define("to-do-item", TodoItem);

    index.html
    
    
      
        Web Components
      
      
        
        
      
    

    あきらめると した
    が で べたように、あなたとWeb Componentsの にはそれらのフレームワークが てられており、Web Componentsも の の を していないし、ブラウザ の もあります(polyfillは えますが)、しばらくは めることをお めします.