web component

浏览器发展至今,很多浏览器已经很好的支持web component了,如果实在需要兼容IE、Edge还可以用pollyfill来增强一下浏览器

最全的使用文档:

  chrome开发者相关:https://developers.google.com/web/fundamentals/web-components/

  vue-cli相关:https://github.com/vuejs/vue-docs-zh-cn/blob/master/vue-web-component-wrapper/README.md#%E5%85%BC%E5%AE%B9%E6%80%A7

下面我们来大概看看怎么使用

test.html:

<!DOCTYPE html>
<html lang="en">

<head>
    <style>
        /* 
         * 可以外部定义web component样式,但是内部的shadow dom,选择器无法命中 
         * 这里定义的样式优先级高于:host定义的样式,就是如果定义display:inline;会覆盖掉:host定义的display:block;
         * 这里也可以定义css变量,在shadow dom里面使用
         **/
        app-drawer { --font-color: grey; line-height: 50px; }
        /* slot进去的可以命中 */
        app-drawer div { font-style: italic }
        /* shadow dom的没法命中 */
        app-drawer p { font-style: italic }
    </style>
</head>

<body class="little">
    <!-- 原生支持的template,用于web component的shadow dom -->
    <template id="temp">
        <!-- 这里的style是跟外界独立开的,相当于vue的scoped -->
        <style>
            :host {
                line-height: 20px;
                display: block;
                cursor: pointer;
                color: var(--font-color, #ff0);
                /* 通常,网络组件的布局/样式/绘制相当独立。在 :host 中使用 CSS containment 可获得更好性能 */
                contain: content;
            }
            /* host-context表示父级如果命中括号里面的选择器则应用里面的样式,如果命中多个,且有冲突则看优先级 */
            :host-context(.big) {
                font-size: 32px;
                font-weight: bold;
            }
            :host-context(.little) {
                font-size: 16px;
            }
            p { color: orange; }
            /* 给插槽引进来的元素添加样式 */
            ::slotted(span) {
                color: var(--font-color, #f00);
            }
        </style>
        <!-- 在这里引入样式表,也是同样只适用于组件内部 -->
        <link rel="stylesheet" href="./style.css">
        <p>
            我是template啦~
        </p>
        <!-- 插槽 -->
        <slot name="slot1"></slot>
        <p>**<slot></slot>**</p>
        <!-- 这里使用script和在template外使用是一样的,this都是window -->
        <script>
            console.log('来自shadow dom的问候')
            console.log(this)
        </script>
    </template>

    <app-drawer class="big">
        <div slot="slot1">我从是slot1插槽进来的div1啦~</div>
        <span>我从是默认插槽进来的span啦~</span>
        <div slot="slot1">我从是slot1插槽进来的div2啦~</div>
    </app-drawer>

    <p>12312</p>

    <!-- 定义自定义web component -->
    <script src="./test.js"></script>
</body>

</html>

test.js:

class AppDrawer extends HTMLElement {

  // 定义组件需要同步更新到DOM的属性
  get open() {
    return this.hasAttribute('open');
  }
  set open(val) {
    if (val) {
      this.setAttribute('open', '');
    } else {
      this.removeAttribute('open');
    }
    this.toggleDrawer();
  }

  // 相当于vue component的beforeCreate
  constructor() {
    super();
    /**
     * 创建shadow dom
     * mode可以时open和closed (建议任何时候都别使用closed,不必要的限制造成很多不便)
     * delegatesFocus 在shadow dom元素focus时,是否也使容器也focus
     */
    let shadowRoot = this.attachShadow({mode: 'closed', delegatesFocus: true});
    // 复制一份template
    const temp = document.querySelector('#temp').content.cloneNode(true)
    // 添加进shadow dom
    shadowRoot.appendChild(temp)
    // 添加事件
    this.addEventListener('click', e => {
      this.open = !this.open
    });
    shadowRoot.querySelector('p').addEventListener('click', e => {
      console.log(e.target)
    });
    // 初始化先执行一次
    this.toggleDrawer()
  }

  /**
   * 生命钩子有:
   * connectedCallback:插入到 DOM 时,相当于vue component的created
   * disconnectedCallback: 从DOM中移除时,相当于vue component的beforeDestroy
   * attributeChangedCallback:属性添加、移除、更新或替换时,有点像vue component的beforeUpdate(不完全等同)
   * adoptedCallback:被移入新的 document时
   */
  
  // 定义组件的方法
  toggleDrawer() {
    this.style.backgroundColor = this.open ? 'red' : 'pink'
  }
}

// 定义自定义组件,名字一定要有"-", 不然浏览器不认为它是web component, 会认为是一个HTMLUnknownElement
customElements.define('app-drawer', AppDrawer);
原文地址:https://www.cnblogs.com/amiezhang/p/11108823.html