组件编程二

内容纲要

WEB一直在往自然言语化方向发展,而组件则是自然语言化很好的方式和体现。

自定义组件

与React或Angular相似,一切自定义标签都继承HTMLElement类:

class WaHaha extends HTMLElement {
  connectedCallback() {
    this.innerHTML = `Hello Indeex`;
  }
}
customElements.define('wa-haha', WaHaha);

注意this指向。

组件生命周期

生命周期是组件的基本功能,当组件从加载到渲染完成,每一步都可以控制:

class WaHaha extends HTMLElement {
  static get observedAttributes() {
    return ['open'];
  }

  attributeChangedCallback(attrName, oldValue, newValue) {
    if (newValue !== oldValue) {
      this[attrName] = this.hasAttribute(attrName);
    }
  }

  connectedCallback() {
    const template = document.getElementById('wa-haha');
    const node = document.importNode(template.content, true);
    this.appendChild(node);
  }
}

observedAttributes初始化或者更新时调用

attributeChangedCallback属性更改回调

connectedCallback初始化设置、元素更新回调

以下示例禁止用于实际项目:

<style type="text/css">
    #modalBtn {
      background: tomato;
      border-radius: 2ch;
      color: #fff;
      padding: 5ch 3ch;
      position: static;
    }
</style>
<wa-haha></wa-haha>
<template id="wahaha-template">
  <style>
    .wrapper {
      opacity: 0;
      transition: visibility 0s, opacity 0.25s ease-in;
    }
    .wrapper:not(.open) {
      visibility: hidden;
    }
    .wrapper.open {
      align-items: center;
      display: flex;
      justify-content: center;
      height: 100vh;
      position: fixed;
        top: 0;
        left: 0;
        right: 0;
        bottom: 0;
      opacity: 1;
      visibility: visible;
    }
    .overlay {
      background: rgba(0, 0, 0, 0.8);
      height: 100%;
      position: fixed;
        top: 0;
        right: 0;
        bottom: 0;
        left: 0;
      width: 100%;
    }
    .dialog {
      background: #ffffff;
      max-width: 800px;
      padding: 1rem;
      position: fixed;
      border-radius: 20px;
    }
    button {
      all: unset;
      cursor: pointer;
      font-size: 1.25rem;
      position: absolute;
        top: 1rem;
        right: 1rem;
    }

    button{
        box-sizing: border-box;
    }

    button:focus{
        border: none;
    }
    button:hover{
        border: 1px solid #1E9BF9;
    }
  </style>
  <div class="wrapper">
  <div class="overlay"></div>
    <div class="dialog" role="dialog" aria-labelledby="title" aria-describedby="content">
      <button class="close" aria-label="Close">叉️</button>
      <h1 id="title">Hello Indeex</h1>
      <div id="content" class="content">
        <p>哇哈哈的模态窗</p>
      </div>
    </div>
  </div>
</template>

<button id="modalBtn">假装是个编辑按钮</button>
class WaHaha extends HTMLElement {
  static get observedAttributes() {
    return ['open'];
  }

  constructor() {
    super();
    this.close = this.close.bind(this);
    this._watchEscape = this._watchEscape.bind(this);
  }

  attributeChangedCallback(attrName, oldValue, newValue) {
    if (oldValue !== newValue) {
      this[attrName] = this.hasAttribute(attrName);
    }
  }

  connectedCallback() {
    const template = document.getElementById('wahaha-template');
    const node = document.importNode(template.content, true);
    this.appendChild(node);


    this.querySelector('button').addEventListener('click', this.close);
    this.querySelector('.overlay').addEventListener('click', this.close);
    this.open = this.open;
  }

  disconnectedCallback() {
    this.querySelector('button').removeEventListener('click', this.close);
    this.querySelector('.overlay').removeEventListener('click', this.close);
  }


  get open() {
    return this.hasAttribute('open');
  }


set open(isOpen) {
    this.querySelector('.wrapper').classList.toggle('open', isOpen);
    this.querySelector('.wrapper').setAttribute('aria-hidden', !isOpen);
    if (isOpen) {
      this._wasFocused = document.activeElement;
      this.setAttribute('open', '');
      document.addEventListener('keydown', this._watchEscape);
      this.focus();
      this.querySelector('button').focus();
    } else {
      this._wasFocused && this._wasFocused.focus && this._wasFocused.focus();
      this.removeAttribute('open');
      document.removeEventListener('keydown', this._watchEscape);
      this.close();
    }
  }


  close() {
    if (this.open !== false) {
      this.open = false;
    }
    const closeEvent = new CustomEvent('wahaha-closed');
    this.dispatchEvent(closeEvent);
  }

  _watchEscape(event) {
    if (event.key === 'Escape') {
        this.close();   
    }
  }
}

customElements.define('wa-haha', WaHaha);

const button = document.getElementById('modalBtn');
button.addEventListener('click', () => {
  document.querySelector('wa-haha').open = true;
})

演示地址:自定义组件

当然,也可以定义纯逻辑组件:

class Ehehe extends HTMLElement {
  connectedCallback() {
    this._onEheheClosed = this._onEheheClosed.bind(this);
    this.addEventListener('ehehe-closed', this._onEheheClosed);
  }

  get ehehes() {
    return Array.from(this.querySelectorAll('one-ehehe'));
  }

  _onEheheClosed(event) {
    const eheheClosed = event.target;
    const nextIndex = this.ehehes.indexOf(eheheClosed);
    if (nextIndex !== -1) {
      this.ehehes[nextIndex].open = true;
    }
  }
}

这个和React很类似。。

code enjoy!😜😜😜

作者:indeex

链接:https://indeex.club

著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。


发表评论

您的电子邮箱地址不会被公开。