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

Detailed steps to modify MySQL stored procedures

Preface In actual development, business requireme...

Web page custom selection box Select

Everyone may be familiar with the select drop-dow...

How to uninstall MySQL cleanly (tested and effective)

How to uninstall Mysql perfectly? Follow the step...

Detailed explanation of redundant and duplicate indexes in MySQL

MySQL allows you to create multiple indexes on th...

React + Threejs + Swiper complete code to achieve panoramic effect

Let’s take a look at the panoramic view effect: D...

The process of deploying a project to another host using Jenkins

environment Hostname ip address Serve Jenkins 192...

Implementation of element shuttle frame performance optimization

Table of contents background Solution New Questio...

Disabled values ​​that cannot be entered cannot be passed to the action layer

If I want to make the form non-input-capable, I se...

Mysql splits string into array through stored procedure

To split a string into an array, you need to use ...

JavaScript Prototype Details

Table of contents 1. Overview 1.1 What is a proto...

Example of fork and mutex lock process in Linux multithreading

Table of contents Question: 1. First attempt 2. R...

Mysql optimization Zabbix partition optimization

The biggest bottleneck of using zabbix is ​​the d...

Linux hardware configuration command example

Hardware View Commands system # uname -a # View k...

How to insert batch data into MySQL database under Node.js

In the project (nodejs), multiple data need to be...

MySQL performance optimization: how to use indexes efficiently and correctly

Practice is the only way to test the truth. This ...