Web Components:原生组件化开发新趋势

曹浩然_前端
2025-06-17 16:07
阅读 769

开篇:Web Components 是什么?有什么用?

开篇:Web Components 是什么?有什么用?

你有没有想过,能不能像搭积木一样来写网页?比如我做好一个按钮、一个菜单、一个输入框,然后在多个页面甚至多个项目里都能直接“搬”过去用,而不用每次都重新写一遍?听起来是不是很棒?

Web Components 就是实现这种“组件化开发”的一种技术。

它是浏览器原生支持的一套技术标准,不需要依赖 React、Vue 这样的框架,就可以让你创建可复用的、封装良好的自定义 HTML 标签

比如你可以自己定义一个 <my-button> 标签,里面是带样式的按钮,还可以响应点击事件,然后在哪都可以使用它:

<my-button>点我试试</my-button>

是不是很酷?这就是 Web Components 的魅力所在!


环境准备:搭建一个适合 Web Components 学习的环境

环境准备:搭建一个适合 Web Components 学习的环境

我们来从最基础的开始,不需要安装复杂的工具就能入门,但我们会逐步引导你进入更真实的开发流程。

1. 基础环境:只需要浏览器和文本编辑器

  • 浏览器: 推荐使用 Chrome 或 Edge(Firefox 也可以)
  • 文本编辑器: VS Code 最为常用,免费且强大(下载地址:https://code.visualstudio.com/

2. 创建你的第一个项目目录结构

新建一个文件夹,比如叫 web-components-demo,在该文件夹中创建以下三个文件:

web-components-demo/
│
├── index.html       <-- 主页
├── main.js          <-- JS 脚本
└── style.css        <-- 样式表(可选)

3. 编写简单的 HTML 测试页面

打开 index.html 文件,写下如下代码:

<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8" />
  <title>Web Components 初体验</title>
  <script type="module" src="main.js"></script>
</head>
<body>
  <h1>欢迎来到 Web Components 小课堂!</h1>
</body>
</html>

💡 注意这里引入 JS 的方式用了 type="module",这是 ES6 模块的标准写法,也是现代浏览器支持 Web Components 的前提之一。

接下来我们在 main.js 中开始编写组件。


核心概念:Web Components 包含哪几个部分?

Web Components 其实不是一项单一的技术,它是由三项核心技术构成的一个组合拳:

  • Custom Elements(自定义元素)
  • Shadow DOM(影子 DOM)
  • HTML Templates(HTML 模板)

下面我们逐一介绍这些概念,并配上简单的示例。


一、Custom Elements:创建你自己的 HTML 标签

这是 Web Components 的核心功能之一——我们可以注册一个全新的 HTML 元素,比如 <hello-world>

实践步骤:

  1. main.js 中加入如下代码:
class HelloWorld extends HTMLElement {
  constructor() {
    super(); // 必须调用一次 super()
    
    // 创建要插入的内容
    const text = document.createTextNode("你好呀,Web Components!");
    
    // 把内容添加到这个元素内部
    this.appendChild(text);
  }
}

// 注册一个新的标签名 'hello-world'
customElements.define('hello-world', HelloWorld);
  1. 打开 index.html,在 body 中加入:
<hello-world></hello-world>
  1. 双击打开 index.html 文件或用浏览器打开:

你应该能看到显示一句话:“你好呀,Web Components!”

🎉 成功了!你刚刚创建了自己的第一个 Web Component!


二、Shadow DOM:给组件加上封装能力

上面的例子虽然能工作,但如果我们想加样式、结构,不让它影响整个页面怎么办?

这就需要用 Shadow DOM(影子 DOM),可以理解为在组件内部建一个“封闭的小房间”,里面的 HTML 和 CSS 都不会被外部干扰。

实践步骤:

修改 main.js

class MyComponent extends HTMLElement {
  constructor() {
    super();
    
    // 创建 shadow root
    const shadow = this.attachShadow({ mode: 'open' });
    
    // 创建元素
    const div = document.createElement('div');
    div.textContent = '我是来自组件的内容';
    
    // 添加样式
    const style = document.createElement('style');
    style.textContent = `
      div {
        color: blue;
        font-size: 20px;
        padding: 10px;
        border: 1px solid #ccc;
        background-color: #f9f9f9;
      }
    `;
    
    // 插入内容与样式
    shadow.appendChild(style);
    shadow.appendChild(div);
  }
}

customElements.define('my-component', MyComponent);

再修改 index.html

<my-component></my-component>

刷新页面你会看到蓝色文字和背景框。而且即使外面有其他 CSS,也改变不了它的样式。

🧠 小贴士: Shadow DOM 有三种模式:

  • open:JS 可以通过 element.shadowRoot 访问
  • closed:JS 不能访问
  • 默认不传参数时就是 open

三、HTML Templates:模板 + 内容分离设计

现在我们要让组件更复杂一些,HTML 结构可能变得很大,这时我们可以通过 <template> 标签把组件的结构提前准备好。

实践步骤:

修改 index.html,添加一个模板:

<template id="card-template">
  <style>
    .card {
      border: 1px solid #ddd;
      padding: 10px;
      width: 200px;
      margin-top: 10px;
      background-color: #fff;
    }

    h2 {
      color: green;
    }
  </style>

  <div class="card">
    <h2>卡片标题</h2>
    <p>这是一个基于 template 构建的卡片组件。</p>
  </div>
</template>

修改 main.js,创建模板化的组件:

class CardComponent extends HTMLElement {
  constructor() {
    super();
    
    const template = document.getElementById('card-template');
    const shadow = this.attachShadow({ mode: 'open' });
    
    // 把模板内容复制一份并插入到组件中
    const clone = document.importNode(template.content, true);
    shadow.appendChild(clone);
  }
}

customElements.define('card-component', CardComponent);

最后,在 index.html 里加上:

<card-component></card-component>

刷新页面后,你会发现页面上多了一个漂亮的卡片,而且结构清晰又容易维护。

🎯 总结一下:

  • Custom Elements 给我们提供创建新标签的能力
  • Shadow DOM 做到了样式隔离和逻辑封装
  • HTML Template 提前保存好结构,便于复用

实战项目:做一个“天气卡片组件”Web Component

为了巩固前面所学,我们来实战做一个简单的 Web Components 项目 —— 天气信息展示组件。

我们将构建一个 <weather-card>,能根据传递的天气数据,显示城市名称、温度和天气状态图标。

第一步:HTML 准备一个容器

index.html 中,先留出使用组件的位置:

<weather-card city="北京" temp="25" condition="晴"></weather-card>

第二步:编写 WeatherCard 类

main.js 中添加以下代码:

class WeatherCard extends HTMLElement {
  constructor() {
    super();
    
    // 获取属性值
    this.city = this.getAttribute('city') || '未知城市';
    this.temp = this.getAttribute('temp') || 0;
    this.condition = this.getAttribute('condition') || '阴天';

    const template = document.getElementById('weather-template');
    const shadow = this.attachShadow({ mode: 'open' });
    
    const clone = document.importNode(template.content, true);

    // 替换模板中的动态值
    const cityName = clone.querySelector('.city-name');
    const temperature = clone.querySelector('.temperature');
    const weatherCondition = clone.querySelector('.condition');

    cityName.textContent = this.city;
    temperature.textContent = `${this.temp} ℃`;
    weatherCondition.textContent = this.condition;

    shadow.appendChild(clone);
  }
}

customElements.define('weather-card', WeatherCard);

第三步:添加模板内容到 HTML

继续在 index.html 中补充模板定义:

<template id="weather-template">
  <style>
    .weather-card {
      border: 1px solid #eee;
      width: 220px;
      padding: 15px;
      box-shadow: 0 2px 5px rgba(0,0,0,0.1);
      background-color: #fafafa;
      font-family: Arial, sans-serif;
    }

    .temperature {
      font-size: 24px;
      color: #f39c12;
    }

    .city-name {
      font-weight: bold;
      font-size: 18px;
      margin-bottom: 5px;
    }
  </style>

  <div class="weather-card">
    <div class="city-name">城市</div>
    <div class="temperature">-- ℃</div>
    <div class="condition">天气</div>
  </div>
</template>

第四步:测试组件

再次刷新 index.html,应该可以看到这样的展示:

北京
25 ℃
晴

一个完整、可复用、样式独立的天气组件就完成了!

👏 恭喜!你已经掌握了 Web Components 的基本开发套路。


常见问题:初学者常问的问题及解答

下面列出几个新手朋友经常遇到的问题,我们一一来解答:


❓1. 自定义元素的名字必须带短横线吗?

是的。
因为 HTML 原生元素没有短横线,例如 <button><div>。为了让浏览器识别这是用户自定义的标签,规定自定义标签必须包含至少一个连字符(hyphen),如 <my-button><user-profile>

⚠️ 错误示范:
<greet>
✔️ 正确命名:
<greet-user>


❓2. 我可以用 jQuery 来操作 Web Components 吗?

当然可以!不过需要注意的是:

  • 如果你用的是 Shadow DOM,外部 JS 是不能直接操作内部节点的
  • 你可以通过暴露 API 的方式来实现交互

例如可以在组件类里定义方法:

class MyComponent extends HTMLElement {
  showData() {
    console.log("组件的数据已加载");
  }
}

然后你在其它地方这样调用:

document.querySelector('my-component').showData();

❓3. 如何在组件内监听点击等事件?

非常简单,只需在 constructor 或生命周期钩子中绑定事件监听器即可。

示例:

class ClickableButton extends HTMLElement {
  constructor() {
    super();
    this.innerText = "点我!";
    this.addEventListener('click', this.handleClick);
  }

  handleClick() {
    alert("按钮被点击啦!");
  }
}

customElements.define('clickable-button', ClickableButton);

❓4. Web Components 支持哪些浏览器?

主流现代浏览器均支持:

  • Chrome ✅
  • Firefox ✅
  • Safari (部分) ⚠️(建议开启“实验性功能”)
  • Edge ✅

对于老旧浏览器如 IE11,需要引入 polyfill


学习建议:下一步学习路线图

你现在已经是 Web Components 的入门玩家了,接下来如果想深入掌握这项技术,可以继续沿着以下几个方向学习:


📚 学习资源推荐

类型 名称 链接
官方文档 MDN Web Components 指南 https://developer.mozilla.org/zh-CN/docs/Web/API/Web_components
视频教程 Web Components 入门讲解 YouTube 上搜 "Web Components tutorial"
开源组件库 Open UI https://open-ui.org/

现代网页界面设计示例-1


🚀 下一步提升方向

  • 🔧 使用 Web Component 构建 UI 组件库(比如按钮、菜单等)
  • 🛠 结合构建工具(Vite / Parcel)打包你的组件
  • 💡 学习 Lit(LitElement、LitHtml)——基于 Web Components 的现代轻量框架
  • 💻 构建跨前端框架的组件系统(React/Vue/Angular 都能使用的组件)
  • 🧪 单元测试:为组件添加自动化测试(推荐使用 Jest)

📝 总结一句话:

学会了 Web Components,你就能写出真正意义上的“通用组件”——哪里都能用,不依赖任何框架。

是不是很吸引人?那就快去动手实践吧!


结束语:组件化是未来的方向

从前端开发的演进历程来看,组件化已经成为主流趋势。而 Web Components 是浏览器层面原生支持的方式,具有极强的生命力和未来前景。

无论你是刚入门前端的新手,还是已有 Vue、React 使用经验的开发者,了解并掌握 Web Components 都会是你职业生涯的重要加分项

祝你早日成为真正的“组件大师”!

评论 0

最热最新
暂无评论
匿名用户Lv.1
0
影响力
0
文章
0
粉丝