Detailed explanation of the underlying principle of defineCustomElement added in vue3.2

Detailed explanation of the underlying principle of defineCustomElement added in vue3.2

Web Components

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

It is equivalent to the browser's native way of defining components, without the need to implement component definitions through frameworks such as Vue or React

customElements

Overview

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

HTMLTemplateElement content template element

Overview

The HTML <template> element is a mechanism for holding client-side content that is not rendered when the page is loaded, but which may be subsequently instantiated at runtime using JavaScript.
Think of a template as a piece of content that can be stored in a document for later use. While the parser does process the contents of the <template> element when loading the page, it does so only to ensure that those contents are valid; the element contents are not rendered.

Common properties

content Gets the content of the DocumentFragment element fragment, which is equivalent to the element fragment created by document.createDocumentFragment().

  <!-- Define the template fragment -->
  <template id="element-template">
    <div>test-template</div>
  </template>

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

    /* Create an HTML fragment via createDocumentFragment*/
    const div = document.createDocumentFragment('div')
    div instanceof DocumentFragment //true

    /* in conclusion*/
    // The template defined on HTML gets its content which is equivalent to the HTML fragment created by createDocumentFragment</script>

ShadowRoot

Overview

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

Mount the shadow DOM via 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="templateEle">
    <style>
      .main{
        color: #f00;
      }
    </style>
    <div class="main">
      I am a template fragment<!-- Using 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">Move</button>
    <button id="remove">Delete</button>
  </div>

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


  <script>
    /* Custom web-components */
    customElements.define('test-shadow-root', class extends HTMLElement {
      /* When the test-shadow-root component is mounted on the DOM, execute the constructor*/
      constructor() {
        super()
        const shadowRoot = this.attachShadow({mode: 'open'}) //Attach shadow DOM to the specified element
        // When the this.attachShadow() method is executed, shadowRoot is mounted in the constructor and can be accessed through this // mode open shadow root element can access the root node from outside js // mode closed denies access to closed shadow root node from outside js // console.log('execution', this)
        const div = document.createElement('div')
        div.textContent = 'I am the content of div'
        // shadowRoot.appendChild()
        // console.log('this', this.shadowRoot)
        shadowRoot.appendChild(div)
        // this.shadowRoot === shadowRoot true
      }
    })

    /* Customize HTMLTemplateElement through template */
    customElements.define('test-template-ele', class extends HTMLElement {
      constructor() {
        super()
        const temEle = document.querySelector('#temEle')
        const templateContent = temEle.content //Get the HTML fragment // console.log('AA', templateContent instanceof DocumentFragment) //true
        // templateContent
        // Create a shadow DOM to mount the template fragment const shadowRoot = this.attachShadow({mode: 'open'})
        // console.log('shadowRoot', shadowRoot)
        shadowRoot.appendChild(templateContent)
      }
    })

    /* Create web-components through js and test life cycle functions*/
      class LifeCycle extends HTMLElement {
        static get observedAttributes() { //You must add the attributes on the component to trigger attributeChangedCallback
          return ['c', 'l'];
        }

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

        connectedCallback() { //When adding, execute console.log('add')
        }
        disconnectedCallback() {//When deleting, execute console.log('disconnectedCallback')
        }
        adoptedCallback() {
          console.log('adoptedCallback')
        }
        attributeChangedCallback() { //When the attribute 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>Updated</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);
      })

      /* Mount components via is*/

      customElements.define('test-is-com', class extends HTMLDivElement {
        constructor() {
          super()
          console.log('mount', this.innerHTML)
          // Through mounting, this is the currently mounted element instance. In this way, some operations can be implemented.}
      }, {extends: 'div'})

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

This is the end of this article about the underlying principles of defineCustomElement added in vue3.2. For more relevant vue3.2 defineCustomElement content, please search for previous articles on 123WORDPRESS.COM or continue to browse the following related articles. I hope everyone will support 123WORDPRESS.COM in the future!

You may also be interested in:
  • Example of Vue's implementation of the underlying code for simulating responsive principles
  • The underlying implementation principle of Vue data two-way binding
  • Summary of Vue's underlying implementation principles
  • How much do you know about the underlying principles of Vue?

<<:  Detailed summary of mysql sql statements to create tables

>>:  How to connect XShell and network configuration in CentOS7

Recommend

How to change the root password of Mysql5.7.10 on MAC

First, start MySQL in skip-grant-tables mode: mys...

MySQL slow_log table cannot be modified to innodb engine detailed explanation

background Getting the slow query log from mysql....

An example of how Vue implements four-level navigation and verification code

Effect: First create five vue interfaces 1.home.v...

Mysql 8.0.18 hash join test (recommended)

Hash Join Hash Join does not require any indexes ...

Getting Started: A brief introduction to HTML's basic tags and attributes

HTML is made up of tags and attributes, which are...

Linux tac command implementation example

1. Command Introduction The tac (reverse order of...

Use native js to simulate the scrolling effect of live bullet screen

Table of contents 1. Basic principles 2. Specific...

How to configure the pdflatex environment in docker

Technical Background Latex is an indispensable to...

Detailed tutorial on installing Tomcat8.5 in Centos8.2 cloud server environment

Before installing Tomcat, install the JDK environ...

Docker network mode and configuration method

1. Docker Network Mode When docker run creates a ...

Six ways to reduce the size of Docker images

Since I started working on Vulhub in 2017, I have...

Detailed explanation of JavaScript array deduplication

Table of contents 1. Array deduplication 2. Dedup...

Implementation of installing and uninstalling CUDA and CUDNN in Ubuntu

Table of contents Preface Install the graphics dr...