Web Components: サンプルその1

1. このページの目的

Web Components のサンプルを実装してみる。

その際、カスタム属性を利用する。

2. デモ

実行結果

コード

HTML

<my-elm interval="1"></my-elm>

JavaScript

class MyElm extends HTMLElement {
  //static get observedAttributes() {
  //  return ['interval'];
  //}

  constructor() {
    super();
    // メソッド内で this を使う場合は必要
    this._onIncClick = this._onIncClick.bind(this);
    this._onDecClick = this._onDecClick.bind(this);
    this._onIntervalIncClick = this._onIntervalIncClick.bind(this);
    this._onIntervalDecClick = this._onIntervalDecClick.bind(this);

    const shadowRoot = this.attachShadow({mode: 'open'});
    shadowRoot.innerHTML = `
<style>
:host {
  display: block;
  contain: content;
}
p.title {
  font-size: 1.2em;
  font-weight: bold;
  margin-top: 0;
}
p[name=output] {
  color: blue;
  margin-left: 1.5em;
}
span[name=interval] {
  display: inline-block;
  margin-right: 1em;
}
button {
  cursor: pointer;
}
</style>
<p class="title">数字を増減させる</p>
<p name="output"></p>
<button name="inc">増</button> <button name="dec">減</button>
<hr>
Interval 属性値: <span name="interval"></span><button name="incInterval">増</button> <button name="decInterval">減</bu
tton>
`;

    this._count = 0;
    this._output = this.shadowRoot.querySelector('p[name=output]');
    this._btnInc = this.shadowRoot.querySelector('button[name=inc]');
    this._btnDec = this.shadowRoot.querySelector('button[name=dec]');
    this._intervalElm = this.shadowRoot.querySelector('span[name=interval]');
    this._btnIntervalInc = this.shadowRoot.querySelector('button[name=incInterval]');
    this._btnIntervalDec = this.shadowRoot.querySelector('button[name=decInterval]');

    this._btnInc.addEventListener('click', this._onIncClick);
    this._btnDec.addEventListener('click', this._onDecClick);
    this._btnIntervalInc.addEventListener('click', this._onIntervalIncClick);
    this._btnIntervalDec.addEventListener('click', this._onIntervalDecClick);
  }

  connectedCallback() {
    this._output.textContent = `0`;
    if (!Number.isInteger(this.interval)) {
      this.interval = 1;
    }
    this._intervalElm.textContent = this.interval;
  }

  disconnectedCallback() {
    if (this._btnInc) {
      this._btnInc.removeEventListener('click', this._onIncClick);
    }
    if (this._btnDec) {
      this._btnDec.removeEventListener('click', this._onDecClick);
    }
    if (this._btnIntervalInc) {
      this._btnIntervalInc.removeEventListener('click', this._onIntervalIncClick);
    }
    if (this._btnIntervalDec) {
      this._btnIntervalDec.removeEventListener('click', this._onIntervalDecClick);
    }
  }

  set interval(value) {
    this.setAttribute('interval', value);
    this._intervalElm.textContent = this.interval;
  }

  get interval() {
    return parseInt(this.getAttribute('interval'));
  }

  _onIncClick() {
    this._count += this.interval;
    this._output.textContent = `${this._count}`;
  }

  _onDecClick() {
    this._count -= this.interval;
    this._output.textContent = `${this._count}`;
  }

  _onIntervalIncClick() {
    this.interval += 1;
  }

  _onIntervalIncClick() {
    this.interval += 1;
  }

  _onIntervalDecClick() {
    this.interval -= 1;
  }

  //attributeChangedCallback(name, oldValue, newValue) {
  //  console.log('attributeChangedCallback()', name, oldValue, newValue);
  //  //this[name] = newValue;
  //}
}
window.customElements.define('my-elm', MyElm);

3. メモ

4. 参考