如何用Vanilla JavaScript创建一个网络组件

433 阅读5分钟

用Vanilla JavaScript创建网络组件

网络应用程序开发是一个相当拥挤的技术领域。有不同类型的框架、库和工具。在开发Web应用时,主要的目标是用封装的组件提供高质量的用户界面(UI)。

因此,当你使用React、Vue、Angular等框架或其他前端框架时,你会将用户界面中的所有东西分解成组件。然而,我们甚至不需要使用框架或库就可以做类似的事情,这就是普通的JavaScript(Vanilla JavaScript)。

本文将讨论什么是Web组件,以及为什么它们会有帮助。最后,它将带你了解如何从头开始创建一个网络组件。

前提条件

网络组件是一个奇妙的、互动的指南。因此,需要对HTML、CSS和JavaScript有良好的理解。

什么是网络组件

网络组件是为网页和应用程序增加功能和特性的一组规范。例如,它们允许HTML元素的可重用性和封装性。

网络组件使你能够建立可以在不同的网络平台、应用程序或页面上重复使用的功能。

网络组件由三种领先的技术组成,用于创建可以在你喜欢的时候重复使用的自定义元素。它们包括。

  • 自定义元素:这些API允许你定义和创建自定义元素以提供所需的用户界面。
  • 影子DOM:启用封装的API。特定的元素从你的主DOM中分离出来,从而防止诸如文档碰撞等问题。
  • HTML模板:允许你声明不在页面上显示的标记模板片段的元素。这些元素被用作模板,可以在多个地方重复使用。

包括chrome、firefox和edge在内的网络浏览器提供对网络组件的支持。这意味着技术,即(自定义元素、阴影DOM和HTML模板)被完全支持。

这张来自webcomponents.org的图片显示了当前web组件的浏览器支持情况。

Browser support

为什么使用网络组件

事实证明,代码的可重用性是很有用的,在网络组件启动之前,要实现一个可重用的用户界面,并在不同的框架和项目中发挥作用是不容易的。

网络组件允许网络开发者使用内置的网络API来构建可重用的UI。这意味着我们可以为一个项目创建一个Web组件,并把它带到另一个项目中,而不需要额外的编码。

用vanilla JavaScript创建一个Web组件

本教程用Vanilla JavaScript或在没有任何框架或库的帮助下创建一个Web组件。

我们将创建一个员工卡的Web组件。它将包含一个用户图片、姓名、ID、工作职位、电话和电子邮件。下面是我们将使用的用户图像。

User Image

我们将首先创建一个index.htmlemployee-card.js 文件。然后复制并粘贴这些代码。

<!DOCTYPE html>
<html lang="en">
<head>
    <title>Web Components</title>
    <style>
      h2{
        color: purple;
      }
    </style>
  
</head>
<body>
    <h2>Employee Card Example</h2>
    <employee-card name="Leah Crystal" avatar=image.png></employee-card>
    <div slot="id"><b>ID:</b> 238</div>
    <div slot="job title"><b>Job Title:</b> Database Administrator</div>
    <div slot="email"><b>Email:</b> lcrystal34@gmail.com</div>
    <div slot="phone"><b>Phone:</b> 292-856-410</div>

     <!-- scripts -->
  <script src="employee-card.js"></script> 
    
</body>
</html>

为了创建一个雇员卡的网络组件,创建一个.js 文件。让我们把它命名为employee-card.js 复制并粘贴这段代码。

const template = document.createElement('template');
template.innerHTML = `
<style>
<style>
  .employee-card {
    font-family: sans-serif;
    background: #f4f6f7;
    width: 250px;
    display: grid;
    grid-template-columns: 1fr;
    margin-bottom: 10px;
  }

</style>
<div class="employee-card">
  <img/>
  <div>
    <h3></h3>
    <div class="details">
      <p><slot name="id"/></p>
      <p><slot name="job title"/></p>
      <p><slot name="email"/></p>
      <p><slot name="phone"/></p>
    </div>
  </div>
</div>`;

class EmployeeCard extends HTMLElement{
 constructor(){
     super();
     this.attachShadow({ mode: 'open'});
     this.shadowRoot.appendChild(template.content.cloneNode(true));
     this.shadowRoot.querySelector('h3').innerText = this.getAttribute('name');
     this.shadowRoot.querySelector('img').src = this.getAttribute('avatar');   
 } 

 connectedCallback(){
   this.h3 = this.getAttribute("name")
   this.render();
 }

 render(){
   this.h3;
 }
}
window.customElements.define('employee-card', EmployeeCard);

上面的代码显示了如何创建一个员工卡网络组件,所以让我们一步一步地理解每一部分。

创建模板

const template = document.createElement('template');

第一步是创建一个HTML内容模板元素<template><template> 元素存放运行页面后不会立即呈现的HTML。

用内容加载模板

template.innerHTML = `
<style>
<style>
  .employee-card {
    font-family: sans-serif;
    background: #f4f6f7;
    width: 250px;
    display: grid;
    grid-template-columns: 1fr;
    margin-bottom: 10px;
  }

</style>
<div class="employee-card">
  <img/>
  <div>
    <h3></h3>
    <div class="details">
      <p><slot name="id"/></p>
      <p><slot name="job title"/></p>
      <p><slot name="email"/></p>
      <p><slot name="phone"/></p>
    </div>
  </div>
</div>
`;

模板元素被存储在一个template 变量中,并与inner HTML 属性相连。innerHTML 属性设置了该元素上的HTML内容。因此,我们可以添加我们想在屏幕上显示的HTML,如<div><p> ,以及更多的HTML元素。

创建HTML元素

class EmployeeCard extends HTMLElement{}

我们创建一个扩展了HTMLElement类的EmployeeCard 。HTMLElement代表所有的HTML元素。

封装HTML元素

constructor(){
     super();
     this.attachShadow({ mode: 'open'});
     this.shadowRoot.appendChild(template.content.cloneNode(true));
     this.shadowRoot.querySelector('h3').innerText = this.getAttribute('name');
     this.shadowRoot.querySelector('img').src = this.getAttribute('avatar');   
 } 

我们有一个空的类。接下来,我们创建一个构造函数并调用基类super() 方法来继承一个类的特征。

一个影子DOM被创建,即this.attachShadow({ mode: 'open'}) ,并成为我们网络组件的封装部分。它使我们的组件的行为独立于Html的其他部分。

你可以让你的影子DOM模式关闭或打开。这意味着你是否可以在你的组件中通过JavaScript访问影子DOM。

Web 组件使我们能够使用影子 DOM,这是浏览器内置的一个功能。因此,如果子元素被添加到一个组件的影子DOM中,它们会被包裹在一个影子根里面。

this.shadowRoot.querySelector('h3').innerText = this.getAttribute('name');
this.shadowRoot.querySelector('img').src = this.getAttribute('avatar')

然后,Web组件的API会得到属性名称和头像,以显示在页面上。

生命周期方法

connectedCallback(){
   this.h3 = this.getAttribute("name")
   this.render();
 }

 render(){
   this.h3;
 }

有四个回调方法定义在自定义元素里面。它们使代码能够在元素发生事件时运行。

让我们看看其中的一些回调方法。

  • connectedCallback: 当组件被插入到HTML文档的DOM时被调用。
  • disconnectedCallback: 当该元素从文档的DOM中移除时被调用。
  • adoptedCallback: 当组件被移动到另一个HTML文档时被调用。
  • attributeChangedCallback: 是当组件的属性被改变时。

创建自定义元素

window.customElements.define('employee-card', EmployeeCard);

我们的网络组件已经创建完毕,但还剩下一个步骤:创建自定义元素。在创建自定义元素时,我们使用JavaScript类EmployeeCard 。在这里,该类继承了HTML Element 的属性。

最后,为了测试我们是否创建了一个员工卡网络组件,用浏览器打开index.html 文件。其输出结果如下所示。

Employee card web component

结语

通过本教程,你已经学会了如何用vanilla JavaScript构建一个简单的Web组件。

希望你已经了解了网络组件,为什么它们是有用的,以及如何建立一个。此外,创建一个网络组件可以使用react.js和vue.js等框架来实现。因此,我鼓励你继续探索和尝试。