More articles

preface

In October, I was busy with some business, and realized some development ideas I understood in the business, and also had a lot of harvest. As a technology, I have the consciousness that I can’t keep up with it step by step. So, I have learned about Web Components without stopping. To be honest, I feel not very comfortable using it, mainly because of many APIS

origin

Three framework vue, react, presents, but the question is not general between components, a lot of good UI library will do three versions let developers use, fixes some problems, but it is undoubtedly a waste of resources, and maintenance costs is high, the need to maintain separate each repository, in order to solve this problem, Web Components came into being to make components more generic and usable at once

The core concept

If you have used the template syntax of Vue, you will notice that Vue is everywhere in Web Components. In fact, Vue also references Web Components in part, introducing some key concepts:

  • Custom elements

Web Components allows you to customize components, just like vue, by writing a component and then using it, for example:

class XwButton extends HTMLElement {}window.customElements.define('xw-button', XwButton)
Copy the code

Once the definition is complete, it can be used in HTML:

<xw-button></xw-button>
Copy the code
  • Shadow DOM

Components can be kept separate from other documents and kept private as separate parts without worrying about JS and CSS clashing with other parts

this._shadowRoot = this.attachShadow({ mode: 'closed' })
Copy the code
  • HTML templates

Web Components provides two tags,

There are many more apis, see Web Components

Let’s use this as a demo to see how web Components complete a component

Button

demo

Button component is relatively simple to write, the code also has corresponding comments, as follows:

const buttonTemplate = document.createElement('template');
// Content template
buttonTemplate.innerHTML = `
  <style>
    :host {
      display: inline-block; 
      padding: 5px 15px;
      box-sizing:border-box; 
      border:1px solid var(--borderColor, #ccc); 
      font-size: 14px; 
      color: var(--fontColor,#333);  
      border-radius: var(--borderRadius,.25em); 
      cursor: pointer;
    }
    :host([type="primary"]) {
      background: #409EFF;
      border-color: #409EFF;
      color: #fff;
    }
    :host([type="success"]) {
      background: #67C23A;
      border-color: #67C23A;
      color: #fff;
    }
    :host([type="warning"]) {
      background: #E6A23C;
      border-color: #E6A23C;
      color: #fff;
    }
    :host([type="error"]) {
      background: #F56C6C;
      border-color: #F56C6C;
      color: #fff;
    }
    :host([disabled]) {
      opacity: .5;
      cursor: not-allowed;
    }
    :host([text]) {
      padding: 0;
      border: none;
      background: none;
    }
    :host([text][type="primary"]) {
      padding: 0;
      border: none;
      background: none;
      color: #409EFF;
    }
    :host([text][type="success"]) {
      padding: 0;
      border: none;
      background: none;
      color: #67C23A;
    }
    :host([text][type="warning"]) {
      padding: 0;
      border: none;
      background: none;
      color: #E6A23C;
    }
    :host([text][type="error"]) {
      padding: 0;
      border: none;
      background: none;
      color: #F56C6C;
    }
    .xw-button {
      background:none; 
      outline:0; 
      border:0; 
      width:100%;
      height:100%;
      padding:0;
      user-select: none;
      cursor: unset;
    }
  </style>
  <div
    class="xw-button"
  >
    <slot></slot>
  </div>
`

class XwButton extends HTMLElement {
  constructor() {
    super(a)// Create shadow DOM (render separately from the main document DOM)
    this._shadowRoot = this.attachShadow({ mode: 'open' });
    // Add elements
    this._shadowRoot.appendChild(buttonTemplate.content.cloneNode(true))}}// Custom elements
window.customElements.define('xw-button', XwButton)

Copy the code

The class section is easy to understand, and the CSS section has a point to explain :host can be understood as representing the entire shadow Dom container. It is not allowed to overwrite the marging and padding styles using wildcards globally, otherwise it will affect the internal style of the shadow Dom container

Here I simply write a button, butto be honest, the style part is quite tiring to write

Input

As follows:

demo

The Input component adds custom events and states

  • Custom events
this.$input.addEventListener('input'.e= > {
  e.stopPropagation()
  const { target: { value } } = e
  // dispatchEvent dispatches events. CustomEvent customizes the time and can carry one parameter
  this.dispatchEvent(new CustomEvent('input', { detail: { value } }))
})
Copy the code

Listen for the input time, throw a new input event, and pass out the vUE value in HTML as follows:

<! -- html -->
<xw-input oninput="onInput(event)"></xw-input>
<! -- js -->
<script>
  const onInput = (event) = > console.log('input', event.detail)
</script>
Copy the code

Vue uses the following:

<template>
  <div>
    <xw-input id="webInput" defaultValue="123"></xw-input>
    {{ value }}
  </div>
</template>
<script>
export default {
  data() {
    return {
      value: '123'
    }
  },
  mounted() {
    document.getElementById('webInput').addEventListener('input', e => {
      const { target: { value } } = e
      this.value = value
    })
  }
}
</script>
Copy the code

Other Common methods

  • ObservedAttributes, attributeChangedCallback

ObservedAttributes returns an array that is listened to in attributeChangedCallback when the data in the array changes.

class XwInput extends HTMLElement {
  constructor() {
    super()}get value() {
    return this.$input.value
  }

  set value(value) {
    this.$input.value = value
  }

  static get observedAttributes() {
    // Listen for changes to the value attribute
    return ['value']}attributeChangedCallback(key, oldVal, newVal) {
    // Value changes trigger events
    console.log(key, oldVal, newVal)
  }

}
Copy the code
  • connectedCallback

Triggered when a custom element is first connected to the DOM

Pros and cons

  • advantage
  1. Native, no additional plug-ins required
  2. Don’t need to compile
  3. The standard CSS/js/HTML
  4. Cross-platform, cross-framework
  5. Low maintenance cost
  • disadvantage
  1. Compatibility is now supported by browsers
  2. There are learning costs, the original foundation to be solid

conclusion

At present, I just made a simple attempt and learned some API, but I still need to operate some in business development (it can be used in production).