Web Components:不用框架也能开发组件

更新日期: 2025-10-28 阅读: 61 标签: 组件

在现代前端开发中,组件化已经成为标准做法。大多数项目使用reactvue框架来构建组件,但其实浏览器本身就提供了一套创建组件的方法,这就是Web Components。

Web Components是一组浏览器原生api,让你能够创建自定义的html标签。这些标签可以在任何地方使用,不依赖任何框架,真正实现"一次编写,到处运行"。


四个核心技术

Web Components由四个关键技术组成:

  1. Custom Elements(自定义元素)
    用来定义新的HTML标签,比如<user-card>、<search-box>等。

  2. Shadow dom(影子DOM)
    创建独立的DOM树,实现样式和结构的隔离,避免与其他元素冲突。

  3. HTML Templates(HTML模板)
    使用<template>标签预定义组件结构,需要时才渲染。

  4. Slots(插槽)
    允许在组件内部插入外部内容,实现内容分发。


动手创建一个用户卡片组件

下面我们一步步创建一个用户信息卡片组件。

第一步:注册自定义标签

首先创建一个JavaScript类来定义组件行为:

class UserCard extends HTMLElement {
  constructor() {
    super();
    // 初始化工作放在这里
  }
}

// 注册自定义标签
customElements.define('user-card', UserCard);

注意:自定义标签名必须包含短横线,这是W3C的标准要求。

第二步:创建Shadow DOM

在构造函数中创建Shadow DOM来实现样式隔离:

constructor() {
  super();
  this.shadow = this.attachShadow({ mode: 'open' });
}

mode: 'open'表示可以通过JavaScript访问Shadow DOM内部,方便调试。

第三步:定义模板结构

在HTML中定义组件模板:

<template id="user-card-template">
  <style>
    .card {
      border: 1px solid #e0e0e0;
      border-radius: 8px;
      padding: 16px;
      max-width: 300px;
      background: white;
      box-shadow: 0 2px 8px rgba(0,0,0,0.1);
      font-family: sans-serif;
    }
    .avatar {
      width: 60px;
      height: 60px;
      border-radius: 50%;
      object-fit: cover;
    }
    .name {
      font-size: 18px;
      margin: 12px 0 8px;
      color: #333;
    }
    .bio {
      color: #666;
      font-size: 14px;
      line-height: 1.4;
      margin: 0;
    }
  </style>
  
  <div class="card">
    <img class="avatar" src="" alt="用户头像">
    <h3 class="name"><slot name="name">用户名</slot></h3>
    <p class="bio"><slot>个人简介</slot></p>
  </div>
</template>

在组件类中使用这个模板:

constructor() {
  super();
  this.shadow = this.attachShadow({ mode: 'open' });
  
  const template = document.getElementById('user-card-template');
  const content = template.content.cloneNode(true);
  this.shadow.appendChild(content);
}

第四步:使用组件

现在可以在HTML中直接使用这个组件:

<user-card>
  <span slot="name">李小明</span>
  前端开发工程师,专注于用户体验和性能优化。
</user-card>

第五步:添加交互功能

让组件更智能,可以响应属性变化:

class UserCard extends HTMLElement {
  constructor() {
    super();
    this.shadow = this.attachShadow({ mode: 'open' });
    
    const template = document.getElementById('user-card-template');
    const content = template.content.cloneNode(true);
    this.shadow.appendChild(content);
  }

  // 定义要监听的属性
  static get observedAttributes() {
    return ['avatar', 'theme'];
  }

  // 属性变化时的回调
  attributeChangedCallback(name, oldValue, newValue) {
    if (name === 'avatar') {
      const avatarImg = this.shadow.querySelector('.avatar');
      avatarImg.src = newValue;
    }
    if (name === 'theme' && newValue === 'dark') {
      const card = this.shadow.querySelector('.card');
      card.style.background = '#333';
      card.style.color = 'white';
    }
  }

  // 组件插入页面时调用
  connectedCallback() {
    console.log('组件已加载');
  }

  // 组件移除时调用
  disconnectedCallback() {
    console.log('组件已移除');
  }
}

使用带属性的组件:

<user-card avatar="user.jpg" theme="dark">
  <span slot="name">张小华</span>
  全栈工程师,热爱开源技术。
</user-card>


Web Components的优势

无需依赖框架
纯原生实现,适合轻量级项目,或者不希望引入大型框架的场景。

跨框架使用
可以在React、Vue、angular等任何框架中使用,兼容性很好。

强样式隔离
Shadow DOM确保组件样式不会影响外部,外部样式也不会影响组件内部。

高可复用性
一次开发,可以在多个项目中重复使用。

渐进式采用
可以在现有项目中逐步引入,不需要重写整个项目。


浏览器支持情况

  • Chrome:54版本以上完全支持

  • Firefox:63版本以上完全支持

  • Safari:10.1版本以上完全支持

  • Edge:79版本以上完全支持

对于旧版本浏览器,可以使用webcomponents.js这个polyfill来提供支持。


适合的使用场景

设计系统
构建企业级的设计系统,确保UI组件在不同项目中保持一致。

微前端
在微前端架构中,各个子应用可以共享基础UI组件。

第三方组件
开发需要嵌入到其他网站的组件,比如客服聊天窗口、分享按钮等。

跨团队协作
不同团队可以共享基础组件,提高开发效率。

传统项目升级
在不使用现代框架的项目中引入组件化开发。


实际开发建议

从简单组件开始
先尝试创建按钮、输入框、卡片等简单组件,熟悉基本概念。

合理使用Shadow DOM
虽然样式隔离很好,但有时候也需要让外部控制组件样式,可以通过css变量来实现:

:host {
  --primary-color: #007bff;
  --border-radius: 8px;
}

.card {
  background-color: var(--primary-color);
  border-radius: var(--border-radius);
}

处理事件
在组件内部处理用户交互:

connectedCallback() {
  this.shadow.querySelector('.card')
    .addEventListener('click', this.handleClick.bind(this));
}

handleClick() {
  this.dispatchEvent(new CustomEvent('card-click', {
    detail: { message: '卡片被点击了' },
    bubbles: true
  }));
}

性能考虑
对于频繁更新的组件,注意避免不必要的重渲染。


总结

Web Components不是要取代React或Vue,而是提供了一种更基础的组件化方案。它让开发者能够用Web标准技术来创建可复用的组件。

学习Web Components有助于理解前端组件化的底层原理。即使你主要使用框架开发,了解这些基础知识也能让你成为更好的开发者。

尝试把你项目中的一些通用组件用Web Components重写,体验原生组件开发的乐趣。你会发现,有时候最简单的方案就是最好的方案。


本文内容仅供个人学习/研究/参考使用,不构成任何决策建议或专业指导。分享/转载时请标明原文来源,同时请勿将内容用于商业售卖、虚假宣传等非学习用途哦~感谢您的理解与支持!

链接: https://fly63.com/article/detial/13072

Vuetify基于vue2.0,为移动而生的组件框架

Vuetify 支持SSR(服务端渲染),SPA(单页应用程序),PWA(渐进式Web应用程序)和标准HTML页面。 Vuetify是一个渐进式的框架,试图推动前端开发发展到一个新的水平。

Vue中插槽的作用_Vue组件插槽的使用以及调用组件内的方法

通过给组件传递参数, 可以让组件变得更加可扩展, 组件内使用props接收参数,slot的使用就像它的名字一样, 在组件内定义一块空间。在组件外, 我们可以往插槽里填入任何元素。slot-scope的作用就是把组件内的数据带出来

react 函数子组件(Function ad Child Component)

函数子组件(FaCC )与高阶组件做的事情很相似, 都是对原来的组件进行了加强,类似装饰者。FaCC,利用了react中children可以是任何元素,包括函数的特性,那么到底是如何进行增强呢?

Vue和React组件之间的传值方式

在现代的三大框架中,其中两个Vue和React框架,组件间传值方式有哪些?组件间的传值是灵活的,可以有多种途径,父子组件同样可以使用EventBus,Vuex或者Redux

vue.js自定义组件directives

自定义指令:以v开头,如:v-mybind。bind的作用是定义一个在绑定时执行一次的初始化动作,观察bind函数,它将指令绑定的DOM作为一个参数,在函数体中,直接操作DOM节点为input赋值。

vue中prop属性传值解析

prop的定义:在没有状态管理机制的时候,prop属性是组件之间主要的通信方式,prop属性其实是一个对象,在这个对象里可以定义一些数据,而这些数据可以通过父组件传递给子组件。 prop属性中可以定义属性的类型,也可以定义属性的初始值。

Web组件简介

Web组件由三个独立的技术组成:自定义元素。很简单,这些是完全有效的HTML元素,包含使用一组JavaScript API制作的自定义模板,行为和标记名称(例如,<one-dialog>)。

web组件调用其他web资源

web组件可以直接或间接的调用其他web资源。一个web组件通过内嵌返回客户端内容的另一个web资源的url来间接调用其他web资源。在执行时,一个web资源通过包含另一个资源的内容或者转发请求到另一个资源直接调用。

vue中如何实现的自定义按钮

在实际开发项目中,有时我们会用到自定义按钮;因为一个项目中,众多的页面,为了统一风格,我们会重复用到很多相同或相似的按钮,这时候,自定义按钮组件就派上了大用场,我们把定义好的按钮组件导出,在全局引用,就可以在其他组件随意使用啦,这样可以大幅度的提高我们的工作效率。

Vue子组件调用父组件的方法

Vue中子组件调用父组件的方法,这里有三种方法提供参考,第一种方法是直接在子组件中通过this.$parent.event来调用父组件的方法,第二种方法是在子组件里用$emit向父组件触发一个事件,父组件监听这个事件就行了。

点击更多...

内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!