Explain the underlying principle of defineCustomElement added to vue3.2 in detail

  • 2021-11-13 06:27:07
  • OfStack

Directory Web Components
customElements
Overview
HTMLTemplateElement Content Template Elements
Overview
Common attributes
ShadowRoot
Overview

Web Components

Web Components is a different set of technologies that allow you to create reusable custom elements (whose functionality is encapsulated outside your code) and use them in your web applications.

It is equivalent to the browser's native way of defining components, and it is not necessary to define components through vue or react frameworks

customElements

Overview

customElements is a read-only property on an Window object, and the interface returns a reference to an CustomElementRegistry object, which can be used to register a new custom elements, or to obtain information about previously defined custom elements.

HTMLTemplateElement Content Template Elements

Overview

HTML Content Template ( < template > ) Element is a mechanism for saving client-side content that is not rendered when the page is loaded, but can then (originally may be) be instantiated at run time using JavaScript.
Treat the template as a fragment of content that can be stored in the document for later use. Although the parser does handle the < template > Element, but only to make sure that content is valid; But the element content is not rendered.

Common attributes

content Gets the contents of an DocumentFragment element fragment
Equivalent to the element fragment created by document. createDocumentFragment (),


  <!--  Definition template Fragment  -->
  <template id="element-template">
    <div>test-template</div>
  </template>

  <script>
    /*  Get template Fragment  */
    const ele = document.getElementById('element-template')
    ele.content instanceof DocumentFragment  //true

    /*  Pass createDocumentFragment Create html Fragment */
    const div = document.createDocumentFragment('div')
    div instanceof DocumentFragment    //true

    /*  Conclusion  */
    //  Defined in html Above template Gets its content Equivalent to and through createDocumentFragment Created html The fragment is 1 A thing 
  </script>

ShadowRoot

Overview

The ShadowRoot interface of Shadow DOM API is the root node of an DOM subtree, rendered separately from the document's main DOM tree.
You can retrieve a reference for an element by using its Element. shadowRoot attribute, assuming it was created by Element. attachShadow () and setting mode to open.

Mount the shadow DOM through Element. attachShadow ()

Complete demo code


<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>

  <test-shadow-root></test-shadow-root>

  <template id="temEle">
    <style>
      .main{
        color: #f00;
      }
    </style>
    <div class="main">
       I am template Fragment 
      <!--  Use slots  -->
      <slot name="header"></slot>
    </div>
  </template>
  <test-template-ele>
    <!--  Define slots  -->
    <style>
      .slot{
        color: rgb(87, 28, 223);
      }
    </style>
    <div class="slot" slot="header"> I am slot</div>
  </test-template-ele>

  <!--  Life cycle test  -->
  <div id="moveDiv">
    <button id="add"> Add </button>
    <button id="update"> Update </button>
    <button id="move"> Moving </button>
    <button id="remove"> Delete </button>
  </div>

  <!--  Pass is Mount  -->
  <div is="test-is-com">
    <div>AAA</div>
  </div>


  <script>
    /*  Customize web-components */
    customElements.define('test-shadow-root', class extends HTMLElement {
      /*  When test-shadow-root Component is mounted to the DOM Executes the constructor when the  */
      constructor() {
        super()
        const shadowRoot = this.attachShadow({mode: 'open'}) // Mounts a shadow on the specified element DOM
        //  When executing  this.attachShadow() Method, shadowRoot In the mounted constructor, you can pass the this Visit 
        // mode open shadow root Element can be retrieved from the js External access root node 
        // mode closed   Refuse from js External access closed shadow root Node 
        // console.log(' Execute ', this)
        const div = document.createElement('div')
        div.textContent = ' I am div Content of '
        // shadowRoot.appendChild()
        // console.log('this', this.shadowRoot)
        shadowRoot.appendChild(div)
        // this.shadowRoot === shadowRoot  true
      }
    })

    /*  Pass template Customize HTMLTemplateElement */
    customElements.define('test-template-ele', class extends HTMLElement {
      constructor() {
        super()
        const temEle = document.querySelector('#temEle')
        const templateContent = temEle.content // Get html Fragment 
        // console.log('AA', templateContent instanceof DocumentFragment) //true
        // templateContent
        //  Create Shadow DOM For mounting template Fragments of 
        const shadowRoot = this.attachShadow({mode: 'open'})
        // console.log('shadowRoot', shadowRoot)
        shadowRoot.appendChild(templateContent)
      }
    })

    /*  Pass js Create web- Component, test life cycle function  */
      class LifeCycle extends HTMLElement {
        static get observedAttributes() {  // You must add a property on the component to trigger attributeChangedCallback
          return ['c', 'l'];
        }

        constructor() {
          super()
          const shadowRoot = this.attachShadow({mode: 'open'})
          const div = `<div>
            <heaher> My head </header>
            <div> Content </div>
            <footer> Tail </footer>
          </div>`
          shadowRoot.innerHTML = div
        }

        connectedCallback() {  // When added, execute the 
          console.log(' Add ')
        }
        disconnectedCallback() {// When deleting, execute the 
          console.log('disconnectedCallback')
        }
        adoptedCallback() {
          console.log('adoptedCallback')
        }
        attributeChangedCallback() {  // When the property is changed 
          console.log('attributeChangedCallback')
        }
      }

      customElements.define('test-life-cycle', LifeCycle)

      const add = document.querySelector('#add')
      const update = document.querySelector('#update')
      const move = document.querySelector('#move')
      const remove = document.querySelector('#remove')
      const moveDiv = document.querySelector('#moveDiv')
      let testLifeDom = null

      function random(min, max) {
        return Math.floor(Math.random() * (max - min + 1) + min);
      }

      add.addEventListener('click', () => {
        testLifeDom = document.createElement('test-life-cycle')  // Create the custom component defined above 
        // console.log('testLifeDom', testLifeDom)
        document.body.appendChild(testLifeDom);
        testLifeDom.setAttribute('l', '100');
        testLifeDom.setAttribute('c', 'red');
        console.log('add', testLifeDom)
      })

      update.addEventListener('click', () => {
        const div = '<div> After updating </div>'
        // console.log('update', testLifeDom.shadowRoot.innerHTML)
        testLifeDom.shadowRoot.innerHTML = div
        testLifeDom.setAttribute('l', random(50, 200));
        testLifeDom.setAttribute('c', `rgb(${random(0, 255)}, ${random(0, 255)}, ${random(0, 255)})`);
      })

      move.addEventListener('click', () => {
        console.log('moveDiv', moveDiv)
        moveDiv.appendChild(testLifeDom)
      })

      remove.addEventListener('click', () => {
        console.log('remove')
        document.body.removeChild(testLifeDom);
      })

      /*  Pass is Mount components  */

      customElements.define('test-is-com', class extends HTMLDivElement {
        constructor() {
          super()
          console.log(' Mount ', this.innerHTML)
          //  By mounting, this Is the currently mounted element instance, in this way, you can implement the 1 Some operations 
        }
      }, {extends: 'div'})

  </script>
</body>
</html>

Related articles: