环球短讯!微前端之Web组件自定义元素示例详解
来源:脚本之家    时间:2022-08-23 17:04:58
目录
我们知道的Web组件使用名称规范组件传参数并可以写模板包括js和cssShadow Dom 影子节点类中的构造函数和钩子函数getter/setter属性和属性反射扩展原生 HTML

我们知道的

第一:我们熟知的HTML标签有 a, p, div, section, ul, li, h2, article, head, body, strong, video, audio 等等


(资料图片)

第二:我们知道,a标签是链接,p标签是段落,div是块级,h2是字体,strong 是粗体,video 可以播放视频,标签可以添加click等事件等等

所以,那么显然我们知道这些标签的名称,而且知道他们的默认的css样式,而且知道他们默认的js事件

由此,我们是否可以自定义标签呢,由我们自己规定名称,规定默认css样式,规定标签默认显示dom结构,规定默认事件呢?

答案当然是肯定的!!下面就介绍主角Web组件

Web组件使用

名称规范

在定义它们时必须使用至少两个单词和一个连字符必须小写自定义元素不能自闭合
class UserCard extends HTMLElement {
  constructor() {
    super();
  }
}
window.customElements.define("user-card", UserCard);

组件传参数并可以写模板包括js和css

组件的样式应该与代码封装在一起,只对自定义元素生效,不影响外部的全局样式,:host伪类,指代自定义元素本身


    
    
        
        
        <script>
            class UserCard extends HTMLElement {
              constructor() {
                super();
                var templateElem = document.getElementById("userCardTemplate");
                var content = templateElem.content.cloneNode(true);
                // 使用name参数
                content.querySelector(".container>.name").innerText = this.getAttribute("name");
                this.appendChild(content);
              }
            }
            window.customElements.define("user-card", UserCard);    
        </script>
    

Shadow Dom 影子节点

没有开启Shadow Dom 前template的内容会直接append到user-card节点上开启Shadow Dom后,template和user-card中间多了一个节点叫shadowRootattachShadow 的mode参数有 open 和 closed 两个不同参数,区别是open时,外部能访问内部节点,closed时完全隔离attachShadow 是大多数标签都支持的,比如 div,p,selection,但是a,ul,li等不支持
<script>
    class UserCard extends HTMLElement {
      constructor() {
        super();
        var shadow = this.attachShadow( { mode: "closed" } );   /******这行开启shadow*****/
        var templateElem = document.getElementById("userCardTemplate");
        var content = templateElem.content.cloneNode(true);
        // 使用name参数
        content.querySelector(".container>.name").innerText = this.getAttribute("name");
        shadow.appendChild(content);         /******这行template添加到shadow*****/
      }
    }
    window.customElements.define("user-card", UserCard);    
</script>

类中的构造函数和钩子函数

class UserCard extends HTMLElement {
  // attributeChangedCallback 能监听的属性
  static get observedAttributes() {return ["name", "url"]; }
  constructor() {
    super();
    // 可以创Shadom,通过this.shadowRoot获取
    // this.attachShadow({ mode: "open" })
  }
  connectedCallback (){
      console.log("钩子,元素append到ducument触发")
  }
  disconnectedCallback (){
      console.log("钩子,元素从document删除触发")
  }
  // 只有observedAttributes 中监听的属性name,url变化会触发下面回调
  attributeChangedCallback (attr, oldVal, newVal){
      console.log("钩子,元素属性改变时触发")
  }
}
window.customElements.define("user-card", UserCard);
姓名何时调用
constructor元素的一个实例被创建。对于初始化状态、设置事件监听器或创建shadow Dom。
connectedCallback每次将元素插入 DOM 时调用。一般主要工作代码写在这里。
disconnectedCallback每次从 DOM 中删除元素时调用。一般写清理的一些代码。
attributeChangedCallback(attrName, oldVal, newVal)观察属性在添加、删除、更新、替换时被调用。只有属性中列出的observedAttributes属性才会收到此回调。
adoptedCallback自定义元素已被移动到一个新的document(例如有人称为document.adoptNode(el))。

getter/setter属性和属性反射

html中attribute 和 类中property 是各自独立,想要建立映射需要手动设置

getter和setter生效


  
  
    
    <script>
      class UserCard extends HTMLElement {
        _name = null;
        constructor() {
          super();
        }
        set name(value) {
          this._name = name;
        }
        get name() {
          return this._name;
        }
      }
      window.customElements.define("user-card", UserCard);
    </script>
  

测试

document.getElementById("usercard").name = "jack"  // 会进入setter
document.getElementById("usercard").name  // 会进入getter,返回jack
document.getElementById("usercard").getAttribute("name")  // 不会进入getter,返回Marty
document.getElementById("usercard").setAttribute("name","bob")  // 不会进入setter
document.getElementById("usercard").getAttribute("name")  // 不会进入getter,返回bob

此时,我们看到 setAttribute 和 gettAttribute 都不会触发类中的 getter 和 setter 方法,但是可以看到如果是 .name 这样的方式可以触发 ,那么改造方式如下:

方式一 重写 setAttribute :


  
  
    
    
    <script>
      const rawSetAttribute = Element.prototype.setAttribute;
      class UserCard extends HTMLElement {
        _name = null;
        constructor() {
          super();
          Element.prototype.setAttribute = function setAttribute(key, value) {
            // 特定的指定name
            if (key == "name") {
              this.name = value; // 这样就能触发 setter
            }
            rawSetAttribute.call(this, key, value);
          };
        }
        set name(value) {
          debugger;
          this._name = name;
        }
        get name() {
          debugger;
          return this._name;
        }
      }
      window.customElements.define("user-card", UserCard);
    </script>
  

方式二 重写 observedAttributes和attributeChangedCallback 监听 name :


  
  
    
    <script>
      class UserCard extends HTMLElement {
        static get observedAttributes() {
          return ["name"];
        }
        _name = null;
        constructor() {
          super();
        }
        attributeChangedCallback(attr, _oldVal, newVal) {
          if (attr == "name") {
            this.name = newVal;
          }
        }
        set name(value) {
          debugger;
          this._name = name;
        }
        get name() {
          debugger;
          return this._name;
        }
      }
      window.customElements.define("user-card", UserCard);
    </script>
  

由此,可以看到组件在页面渲染时会进入setter方法,而且 setAttribute,getAttribute 均进入到setter方法

document.getElementById("usercard").setAttribute("name","bob")  // 会进入setter
document.getElementById("usercard").getAttribute("name")  // 会进入getter,返回bob

扩展原生 HTML

假设您想创建一个更高级的 调用方式二:

let button = document.createElement("button", {is: "fancy-button"});
button.textContent = "Fancy button!";
button.disabled = true;
document.body.appendChild(button);
调用范式三
let button = new FancyButton();
button.textContent = "Fancy button!";
button.disabled = true;

以上就是微前端之Web组件自定义元素示例详解的详细内容,更多关于微前端Web组件自定义元素的资料请关注脚本之家其它相关文章!

关键词: 构造函数 相关文章 我们看到 我们熟知 一个新的

上一篇:

下一篇:

X 关闭

X 关闭