react和vue中自定义标签的原理在这里

文章目录

  • 前言
  • 一、自定义元素是什么
    • 1 乱写的标签
  • 二、使用步骤
    • 1 自定义标签
    • 2 添加web组件内容
    • 3结合template模板标签使用
    • 4 自定义元素的生命周期方法
  • 三, 反射自定义属性
  • 总结


前言

  • 如果你是用vue,react这些框架,就会很熟悉自定义元素的概念.
  • 自定义元素用面向对象风格,可创建自定义的,复杂的,可重用的元素.

一、自定义元素是什么

  • 浏览器会将无法识别的元素整合进DOM,但这些元素也不会起到任何作用.
  • 而自定义的标签会标称HTMLElement实例.

1 乱写的标签

    document.body.innerHTML = `
    这是随便写的
    `;
    console.log(document.querySelector('x-foo') instanceof HTMLElement);  // true
    console.log(HTMLElement); // ƒ HTMLElement() { [native code] }

二、使用步骤

1 自定义标签

  • 如果给x-foo定义复杂的行为,也将其纳入DOM的声明周期管理.
  • 需要使用customElements.define( ) 创建自定义元素.

基本的定义

    class FooElement extends HTMLElement { }
    // 注册为自定义标签
    customElements.define('x-foo', FooElement);

    document.body.innerHTML = `自定义元素`;

    console.log(document.querySelector('x-foo') instanceof FooElement);  // true

在页面中引用自定义元素

  // 自定义元素的类中继承了HTMLElement必须先调用super()
    class FooElement extends HTMLElement {
      constructor() {
        super();
        console.log('x-foo');

      }
    }

    customElements.define('x-foo', FooElement);

    document.body.innerHTML = `
     11
    22 
    33 `;

2 添加web组件内容

  • 每次将自定义元素添加到DOM中,都会调用其类的构造函数
  • 直接给自定义元素添加DOM,会抛出错误.
  • 但可以为自定义元素添加影子DOM
    class FooElement extends HTMLElement {
      constructor() {
        super();

        // this表示当前的自定义标签实例
        // 设置为影子DOM
        this.attachShadow({ mode: 'open' });
        this.shadowRoot.innerHTML = `

自定义元素

`
; } } customElements.define('x-foo', FooElement); document.body.innerHTML += ' '

react和vue中自定义标签的原理在这里_第1张图片

3结合template模板标签使用

// html代码
 <template id="x-foo-tpl">
    <p>template模板的内容</p>
  </template>
// js代码
    const template = document.querySelector('#x-foo-tpl');

    class FooElement extends HTMLElement {
      constructor() {
        super();
        console.log(this);
        // 设置自定义标签为影子DOM
        this.attachShadow({ mode: 'open' });
        // 克隆template中的内容给自定标签
        this.shadowRoot.appendChild(template.content.cloneNode(true))
      }

    }
    customElements.define('x-foo', FooElement);
    document.body.innerHTML += ' ';

react和vue中自定义标签的原理在这里_第2张图片

4 自定义元素的生命周期方法

  • constructor() 创建自定元素或将已有DOM升级为自定义DOM时调用.
  • connectedCallback() 每次将自定义元素添加到DOM中时,调用
  • disconnectedCallback() 将自定义元素,移除时调用
  • attrbuteChangeCallback() 在属性值发生变化时调用,初始值的设置也算一次变化.
  • adoptedCallback() 通过docunment.adopNode() 将自定义元素移动到新文档时调用.
     class FooElement extends HTMLElement {
      constructor() {
         super();
         console.log('被创建..');

      }
       connectedCallback() {
         console.log('添加到DOM');

      }
       disconnectedCallback() {
         console.log('被从DOM中移除');
       }
     }

    // customElements.define('x-foo', FooElement);

    // 创建
    const fooTag = document.createElement('x-foo');
    // 追加到DOM中
    document.body.appendChild(fooTag);
    // 移除
    document.body.removeChild(fooTag);

声明周期方法,可以让我们在自定义标签的每个阶段,进行不同的操作.

三, 反射自定义属性

  • 自定义属性是DOM实体又是js对象,两者之间的变化应该是同步的,
  • 对DOM的修改应该映射到js对象中.
  • 对js对象的修改也应该映射到DOM中.

修改js对象的值,映射到DOM中

 document.body.innerHTML = '自定义元素';

    class FooElement extends HTMLElement {
      constructor() {
        super();
        this.bar = true
      }
      get bar() {
        return this.getAttribute('bar')
      }
      set bar(val) {
        this.setAttribute('bar', val);
        console.log('被设置属性...');

      }

    }

    customElements.define('x-foo', FooElement);

    // console.log(document.body.innerHTML);

    // 获取标签
    const foo = document.querySelector('x-foo');
    // console.log(foo);
    // 重新设置属性
    foo.setAttribute('bar', 'hello')

DOM映射到js对象


    class FooElement extends HTMLElement {
      // 监听自定义元素属性
      static get observedAttributes() {
        // 返回应该触发 attributeChangeCallback 执行的属性
        return ['bar']
      }
      get bar() {
        return this.getAttribute('bar')
      }
      set bar(val) {
        this.setAttribute('bar', val);
        console.log('被设置属性...');

      }
      //  observedAttributes() 监听到变化,则通知该方法
      attributeChangedCallback(name, oldValue, newValue) {
        if (oldValue !== newValue) {
          console.log('修改之前的值', oldValue);
          console.log('修改之后的值', newValue);
          this[name] = newValue;


        }
      }

    }

    customElements.define('x-foo', FooElement);

    document.body.innerHTML = `初始设置 `;

    document.querySelector('x-foo').setAttribute('bar', '小甜甜')

react和vue中自定义标签的原理在这里_第3张图片这里使用的set和get都是,ES6中新的特性.


总结

  • 自定义标签,主要是用class定义,继承自HTMLElement,构造函数中使用super调用父类的构造方法.
  • 自定义标签类,必须用 customElements.define()进行注册.
  • 给自定义标签中,添加内容,可以用影子组件,也可以用template模板标签.

别跑,据说给我一键三联的人写代码都没Bug! 您的支持就是我最大的动力!

我是飞翔,
愿您日有所长!

你可能感兴趣的:(原生js,javascript,前端,html5,vue.js)