微前端之Web组件自定义元素示例详解_JavaScript

来源:脚本之家  责任编辑:小易  
目录
我们知道的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伪类,指代自定义元素本身

<html>
    <head></head>
    <body>
        <user-card name="Marty Mcfly"></user-card>
        <template id="userCardTemplate">
          <div class="profile-picture">
            <img src="marty.png" alt="Marty Mcfly" />
          </div>
          <div class="name"></div>
          <style>
           :host {
             display: flex;
             align-items: center;
             width: 450px;
             height: 180px;
             background-color: #d4d4d4;
             border: 1px solid #d5d5d5;
             box-shadow: 1px 1px 5px rgba(0, 0, 0, 0.1);
             border-radius: 3px;
             overflow: hidden;
             padding: 10px;
             box-sizing: border-box;
             font-family: 'Poppins', sans-serif;
           }
           .image {
             flex: 0 0 auto;
             width: 160px;
             height: 160px;
             vertical-align: middle;
             border-radius: 5px;
           }
        </style>
        </template>
        <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>
    </body>
</html>

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生效

<html>
  <head></head>
  <body>
    <user-card id="usercard" name="Marty"></user-card>
    <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>
  </body>
</html>

测试

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 :

<html>
  <head></head>
  <body>
    <user-card id="usercard" name="Marty"></user-card>
    <user-card id="uc" name="Marty Mcfly"></user-card>
    <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>
  </body>
</html>

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

<html>
  <head></head>
  <body>
    <user-card id="uc" name="Marty Mcfly"></user-card>
    <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>
  </body>
</html>

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

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

扩展原生 HTML

假设您想创建一个更高级的<button>. 与其复制<button>的行为和功能,更好的选择是使用自定义元素逐步增强现有元素。

扩展现有元素的主要好处是获得其所有特性(DOM 属性、方法、可访问性)。Safari浏览器兼容性待提高要扩展一个元素,您需要创建一个继承自正确 DOM 接口的类定义。前面例子都是继承HTMLElement,现在更多继承例如,按钮HTMLButtonElement,图片HTMLImageElement
class FancyButton extends HTMLButtonElement {
    constructor() {
        super(); 
        this.addEventListener('click', e => this.drawRipple(e.offsetX, e.offsetY));
    }
    drawRipple(x, y) {
        let div = document.createElement('div');
        div.classList.add('ripple');
        this.appendChild(div);
        div.style.top = `${y - div.clientHeight/2}px`;
        div.style.left = `${x - div.clientWidth/2}px`;
        div.style.backgroundColor = 'currentColor';
        div.classList.add('run');
        div.addEventListener('transitionend', e => div.remove());
    }
}
customElements.define('fancy-button', FancyButton, {extends: 'button'});

注意:扩展基础元素时,对的调用 define() 略有变化。必需的第三个参数告诉浏览器您正在扩展哪个标签

调用方式一:
<button is="fancy-button" disabled>Fancy button!</button>
调用方式二:
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组件自定义元素的资料请关注真格学网其它相关文章!

您可能感兴趣的文章:JavaScript WebAPI、DOM、事件和操作元素实例详解Web纯前端“旭日图”实现元素周期表web2.0中流行的设计元素:颜色Web三大组件之Filter,Listener和Servlet详解Web componentd组件内部事件回调及痛点剖析

  • 本文相关:
  • git?hooks的作用及创建使用示例详解
  • 微信小程序 教程之事件
  • 微信小程序promsie.all和promise顺序执行
  • js常用正则表达式超全集(密码强度校验,金额校验,ie版本,ipv4,ipv6校验)
  • 从原生javascript到react深入理解
  • 带你彻底理解javascript中的原型对象
  • 网页里控制图片大小的相关代码
  • 微信小程序(十二)text组件详细介绍
  • 详解 typescript 枚举类型
  • 微信小程序 wx.request(接口调用方式)详解及实例
  • 在web前端当中,什么是元素?
  • win7如何自定义web桌面
  • JS自定义函数对web前端上传的文件进行类型大小判断
  • web平台自定义设置要多久?
  • alook小组件自定义设置
  • 求可视图化编辑的web前端框架,可随意自定义组态画面
  • C#在WEB程序中如何创建和使用自定义组件
  • argis10.1缺gui组件无法加载自定义命令
  • 有没有好的j2ee平台的工作流组件,web自定义表单,web可视化流...
  • 有没有好的web自定义表单,web可视化流程定义组件?最好是基...
  • web前端页面布局,一般情况用哪些标签最好,可以尽可能地达到...
  • WEB中的重要元素有()。
  • 如何为ionicwebapp开发自定义插件?
  • 电脑系统升级卡在web平台自定义设置怎么办?
  • 电脑开机黑屏显示web平台自定义设罝
  • java web中做自定义报表怎么做
  • phpweb自定义内容怎么编写
  • 网站首页网页制作脚本下载服务器操作系统网站运营平面设计媒体动画电脑基础硬件教程网络安全javascriptasp.netphp编程ajax相关正则表达式asp编程jsp编程编程10000问css/htmlflex脚本加解密web2.0xml/rss网页编辑器相关技巧安全相关网页播放器其它综合dart首页javascriptjavascript webapi、dom、事件和操作元素实例详解web纯前端“旭日图”实现元素周期表web2.0中流行的设计元素:颜色web三大组件之filter,listener和servlet详解web componentd组件内部事件回调及痛点剖析git?hooks的作用及创建使用示例详解微信小程序 教程之事件微信小程序promsie.all和promise顺序执行js常用正则表达式超全集(密码强度校验,金额校验,ie版本,ipv4,ipv6校验)从原生javascript到react深入理解带你彻底理解javascript中的原型对象网页里控制图片大小的相关代码微信小程序(十二)text组件详细介绍详解 typescript 枚举类型微信小程序 wx.request(接口调用方式)详解及实例微信小程序 数组(增,删,改,查)等操作实例详解微信小程序 for 循环详解微信小程序 小程序制作及动画(animation样式)详解微信小程序 input输入框控件详解及实例(多种示例)微信小程序 input输入框详解及简单实例微信小程序 传值取值的几种方法总结微信小程序 时间格式化(util.formattime(ne微信小程序中使元素占满整个屏幕高度实现方法微信小程序 wx.request(接口调用方式)详解及实例微信小程序通过api接口将json数据展现到小程序示例typescript?泛型推断实现示例详解前端ai机器学习在浏览器中训练模型微信小程序 post请求的实例详解如何编写高质量 javascript 代码wasm+js实现文件获取md5示例详解微信小程序 php生成带参数二维码js 4个超级实用的小技巧 提升开发效率js控制表格隔行变色微信小程序 buffer缓冲区的详解微信小程序 选项卡的简单实例
    免责声明 - 关于我们 - 联系我们 - 广告联系 - 友情链接 - 帮助中心 - 频道导航
    Copyright © 2017 www.zgxue.com All Rights Reserved