Основной принцип defineCustomElement, добавленный vue3.2

JavaScript Vue.js
Основной принцип defineCustomElement, добавленный vue3.2

Это 8-й день моего участия в августовском испытании обновлений.Подробности о событии:Испытание августовского обновления

Web Components

Web Components— это набор различных технологий, которые позволяют вам создавать повторно используемые пользовательские элементы (их функциональность инкапсулирована вне вашего кода) и использовать их в своих веб-приложениях. Это эквивалентно собственному способу определения компонентов в браузере без реализации определения компонентов с помощью таких фреймворков, как vue или react.

customElements

Обзор

customElementsЭто свойство только для чтения на объекте окна, интерфейс возвращает ссылку на объект CustomleMenteGistry, который можно использовать для регистрации новых пользовательских элементов, или получить информацию о ранее определенных пользовательских элементах.

HTMLTEMALDELEMETE CONTENT

Обзор

Шаблон содержимого HTML (<template>) — это механизм для хранения содержимого на стороне клиента, которое не отображается при загрузке страницы, но затем может быть создано во время выполнения с помощью JavaScript. Думайте о шаблоне как о фрагменте контента, который можно сохранить в документе для последующего использования. Хотя парсер обрабатывает при загрузке страницы<template>Содержимое элемента, но только для того, чтобы убедиться, что содержимое допустимо, однако содержимое элемента не будет отображаться.

Общие свойства

contentПолучить содержимое фрагмента элемента DocumentFragment Элемент, эквивалентный Document.createddocumentFragment(),

  <!-- 定义template片段 -->
  <template id="element-template">
    <div>test-template</div>
  </template>

  <script>
    /* 获取template片段 */
    const ele = document.getElementById('element-template')
    ele.content instanceof DocumentFragment  //true

    /* 通过createDocumentFragment创建html片段*/
    const div = document.createDocumentFragment('div')
    div instanceof DocumentFragment    //true

    /* 结论 */
    // 定义在html上的template获取它的content相当于和通过createDocumentFragment创建的html片段是一个东西
  </script>

ShadowRoot

Обзор

Интерфейс ShadowRoot API Shadow DOM — это корневой узел поддерева DOM, который отображается отдельно от основного дерева DOM документа.

Вы можете получить ссылку на элемент, используя его свойство Element.shadowRoot, предполагая, что он был создан с помощью Element.attachShadow() с установленным режимом открытия.

Прикрепите теневой DOM через Element.attachShadow()

полный демонстрационный код

<!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">
      我是template片段
      <!-- 使用插槽 -->
      <slot name="header"></slot>
    </div>
  </template>
  <test-template-ele>
    <!-- 定义插槽 -->
    <style>
      .slot{
        color: rgb(87, 28, 223);
      }
    </style>
    <div class="slot" slot="header">我是slot</div>
  </test-template-ele>

  <!-- 生命周期测试 -->
  <div id="moveDiv">
    <button id="add">添加</button>
    <button id="update">更新</button>
    <button id="move">移动</button>
    <button id="remove">删除</button>
  </div>

  <!-- 通过is挂载 -->
  <div is="test-is-com">
    <div>AAA</div>
  </div>


  <script>
    /* 自定义web-components */
    customElements.define('test-shadow-root', class extends HTMLElement {
      /* 当test-shadow-root组件被挂载到DOM上时,执行构造函数 */
      constructor() {
        super()
        const shadowRoot = this.attachShadow({mode: 'open'}) //给指定的元素挂载影子DOM
        // 当执行 this.attachShadow()方法时,shadowRoot被挂载构造函数中,可以通过this访问
        // mode open shadow root元素可以从js外部访问根节点
        // mode closed  拒绝从js外部访问关闭的shadow root节点
        // console.log('执行', this)
        const div = document.createElement('div')
        div.textContent = '我是div的内容'
        // shadowRoot.appendChild()
        // console.log('this', this.shadowRoot)
        shadowRoot.appendChild(div)
        // this.shadowRoot === shadowRoot  true
      }
    })

    /* 通过template自定义HTMLTemplateElement */
    customElements.define('test-template-ele', class extends HTMLElement {
      constructor() {
        super()
        const temEle = document.querySelector('#temEle')
        const templateContent = temEle.content //获取html片段
        // console.log('AA', templateContent instanceof DocumentFragment) //true
        // templateContent
        // 创建影子DOM,用于挂载template的片段
        const shadowRoot = this.attachShadow({mode: 'open'})
        // console.log('shadowRoot', shadowRoot)
        shadowRoot.appendChild(templateContent)
      }
    })

    /* 通过js创建web-组件,测试生命周期函数 */
      class LifeCycle extends HTMLElement {
        static get observedAttributes() {  //必须添加组件上的属性,才能触发attributeChangedCallback
          return ['c', 'l'];
        }

        constructor() {
          super()
          const shadowRoot = this.attachShadow({mode: 'open'})
          const div = `<div>
            <heaher>我的头</header>
            <div>内容</div>
            <footer>尾部</footer>
          </div>`
          shadowRoot.innerHTML = div
        }

        connectedCallback() {  //添加时,执行
          console.log('添加')
        }
        disconnectedCallback() {//删除时,执行
          console.log('disconnectedCallback')
        }
        adoptedCallback() {
          console.log('adoptedCallback')
        }
        attributeChangedCallback() {  //属性被改变时
          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')  //创建上面定义的自定义组件
        // 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>更新后</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);
      })

      /* 通过is挂载组件 */

      customElements.define('test-is-com', class extends HTMLDivElement {
        constructor() {
          super()
          console.log('挂载', this.innerHTML)
          // 通过挂载,this,就是当前被挂载的元素实例,通过这种方式,可以实现一些操作
        }
      }, {extends: 'div'})

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