1.什么是自定义元素(Custom Elements)

212 阅读2分钟

html原生元素/标签有<div><span><p><img><video>等等..., 除了这些原生元素之外, W3C还制定了Custom Elements(自定义元素)标准, 它允许用户自定义注册元素, 例如定义fl-tree来渲染树形数据, 之后就可以在原生html使用<fl-tree>来渲染数据了, 由于自定义元素是原生支持的, 所以它天然跨框架, 不管是vue还是react亦或是angular都可以使用

这里简单用原生js实现一个自定义元素fl-button

新建一个xxx.html文件, 复制下面代码, 用浏览器打开即可看到效果

<!DOCTYPE html>
<html>
  <head>
    <title>FL-Button Demo</title>
  </head>
  <body>
    <!-- 默认按钮 -->
    <fl-button>默认按钮</fl-button>

    <!-- 主要按钮 -->
    <fl-button type="primary">主要按钮</fl-button>

    <!-- 成功按钮 -->
    <fl-button type="success">成功按钮</fl-button>

    <!-- 危险按钮 -->
    <fl-button type="danger">危险按钮</fl-button>

    <!-- 禁用状态 -->
    <fl-button disabled>禁用按钮</fl-button>
    
    <script>
    	class FlButton extends HTMLElement {
        constructor() {
          super();
          // 创建 Shadow DOM
          this.attachShadow({ mode: 'open' });

          // 初始化样式和结构
          this.render();
        }

        // 监听的属性
        static get observedAttributes() {
          return ['type', 'disabled'];
        }

        // 属性变化时的回调
        attributeChangedCallback(name, oldValue, newValue) {
          if (oldValue !== newValue) {
            this.render();
          }
        }

        // 渲染方法
        render() {
          const type = this.getAttribute('type') || 'default';
          const disabled = this.hasAttribute('disabled');

          this.shadowRoot.innerHTML = `
            <style>
              :host {
                display: inline-block;
              }

              .fl-button {
                padding: 8px 16px;
                border-radius: 4px;
                border: none;
                cursor: pointer;
                font-size: 14px;
                transition: all 0.3s;
              }

              .fl-button:hover {
                opacity: 0.8;
              }

              .fl-button:active {
                opacity: 0.6;
              }

              .fl-button[disabled] {
                cursor: not-allowed;
                opacity: 0.5;
              }

              /* 类型样式 */
              .fl-button.default {
                background-color: #e0e0e0;
                color: #333;
              }

              .fl-button.primary {
                background-color: #1976d2;
                color: white;
              }

              .fl-button.success {
                background-color: #4caf50;
                color: white;
              }

              .fl-button.danger {
                background-color: #f44336;
                color: white;
              }
            </style>

            <button 
              class="fl-button ${type}"
              ?disabled="${disabled}"
            >
              <slot></slot>
            </button>
          `;
        }
      }

      // 注册fl-button组件
      customElements.define('fl-button', FlButton);
    </script>
  </body>
</html>

Custom ElementsHTML ImportsHTML TemplateShadow DOM标准统称为Web component规范, 自定义元素也称为web component

这里我们一般只需关注Custom ElementsShadow DOM, 后面再详细讲解.

web component和我们平常时用到的组件库(例如Element Plus)是有本质上的区别的:

  1. web component不依赖框架, 而Element Plus只能在vue3项目中使用
  2. web component一般搭配Shadow DOM一起使用, 使用Shadow DOM后, 样式将被隔离, 普通的样式穿透不会影响web component的样式 (这个特性有好有坏)
  3. web component的插槽和vue3的插槽有较大差别, web component不支持作用域插槽
  4. web component是真实注册了自定义元素, 在渲染到页面也会保留自定义元素名称, 而Element Plus的组件最后通通会被编译成原生元素

下一章讲解: 2.跨框架webcomponent组件库