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 mysql password on the Xampp server (with pictures)

Today, I found out while working on PHP that if w...

How to implement vue page jump

1. this.$router.push() 1. Vue <template> &l...

Getting Started Tutorial for Beginners ⑨: How to Build a Portal Website

Moreover, an article website built with a blog pro...

Example of automatic stop effect after text scrolling

The effect is very simple, just copy the following...

Detailed explanation of html-webpack-plugin usage

Recently, I used html-webapck-plugin plug-in for ...

How to use Flex layout to achieve scrolling of fixed content area in the head

The fixed layout of the page header was previousl...

Div picture marquee seamless connection implementation code

Copy code The code is as follows: <html> &l...

Tomcat Server Getting Started Super Detailed Tutorial

Table of contents 1. Some concepts of Tomcat –1, ...

Detailed explanation of MySQL sql99 syntax inner join and non-equivalent join

#Case: Query employee salary levels SELECT salary...

10 bad habits to avoid in Docker container applications

There is no doubt that containers have become an ...

Steps for Docker to build its own local image repository

1. Environment and preparation 1. Ubuntu 14.04 2....

CSS tips for controlling animation playback and pause (very practical)

Today I will introduce a very simple trick to con...

Implementation of mysql decimal data type conversion

Recently, I encountered a database with the follo...

Mobile web screen adaptation (rem)

Preface I recently sorted out my previous notes o...

The three new indexes added in MySQL 8 are hidden, descending, and functions

Table of contents Hidden, descending, and functio...