利用JavaScript和HTML编写你的第一个网络组件

177 阅读5分钟

网络组件是JavaScript和HTML等开源技术的集合,允许你创建可以在网络应用中使用和重用的自定义元素。你创建的组件是独立于你的其他代码的,所以它们很容易在许多项目中重用。

最重要的是,它是一个平台标准,由所有主要的现代浏览器支持。

网络组件里有什么?

  • 自定义元素。这个JavaScript API允许你定义新类型的HTML元素。
  • 影子DOM。这个JavaScript API提供了一种方法,将一个隐藏的单独的文档对象模型(DOM)附加到一个元素。这通过保持样式、标记结构和行为与页面上的其他代码隔离来封装你的网络组件。它确保样式不会被外部样式覆盖,或者反过来说,你的网络组件的样式不会 "泄露 "到页面的其他部分**。**
  • HTML模板。该元素允许你定义可重复使用的DOM元素。该元素及其内容不在DOM中呈现,但仍可使用JavaScript进行引用。

你可以用你喜欢的文本编辑器和JavaScript编写一个简单的网络组件。这个方法使用bootstrap来生成简单的样式,然后创建一个简单的卡片式Web组件来显示作为属性传递给它的地点的温度。该组件使用Open Weather API,这需要你通过登录生成一个APPID/APIKey。

调用这个网络组件的语法需要地点的经度和纬度。

<weather-card longitude='85.8245' latitude='20.296' />

创建一个名为weather-card.js的文件,其中将包含你的网络组件的所有代码。从定义你的组件开始。这可以通过创建一个模板元素并在其中添加一些简单的HTML元素来完成。

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

template.innerHTML = `
  <div class="card">
    <div class="card-body"></div>
  </div>
`

开始定义WebComponent类和它的构造函数。

class WeatherCard extends HTMLElement {
  constructor() {
    super();
    this._shadowRoot = this.attachShadow({ 'mode': 'open' });
    this._shadowRoot.appendChild(template.content.cloneNode(true));
  }
  ….
}

构造函数附加了shadowRoot并将其设置为开放模式。然后,模板被克隆到shadowRoot。

接下来,访问属性。这些是经度和纬度,你需要它们来向Open Weather API发出GET请求。这需要在connectedCallback 函数中完成。你可以使用getAttribute 方法来访问这些属性,或者定义获取器来将它们绑定到这个对象。

get longitude() {
  return this.getAttribute('longitude');
}
get latitude() {
  return this.getAttribute('latitude');
}

现在定义connectedCallBack 方法,每当天气数据被挂起时,该方法就会取回天气数据。

connectedCallback() {
  var xmlHttp = new XMLHttpRequest();
  const url = `http://api.openweathermap.org/data/2.5/weather?lat=${this.latitude}&lon=${this.longitude}&appid=API_KEY`
  xmlHttp.open("GET", url, false);
  xmlHttp.send(null);
  this.$card = this._shadowRoot.querySelector('.card-body');
  let responseObj = JSON.parse(xmlHttp.responseText);
  let $townName = document.createElement('p');
  $townName.innerHTML = `Town: ${responseObj.name}`;
  this._shadowRoot.appendChild($townName);
  let $temperature = document.createElement('p');
  $temperature.innerHTML = `${parseInt(responseObj.main.temp - 273)} °C`
  this._shadowRoot.appendChild($temperature);
}

一旦天气数据被检索到,额外的HTML元素就会被添加到模板中。现在,你的类被定义了。

最后,通过使用方法window.customElements.define ,定义并注册一个新的自定义元素。

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

第一个参数是自定义元素的名称,第二个参数是定义的类。这里是整个组件的链接。

你已经写好了你的第一个网络组件!现在是时候把它带到DOM中去了。要做到这一点,你必须在你的HTML文件中加载带有你的网络组件定义的JavaScript文件(命名为index.html)。

<!DOCTYPE html>
<html>

<head>
  <meta charset="UTF-8">
</head>

<body>
  <weather-card longitude='85.8245' latitude='20.296'></weather-card>
  <script src='./weather-card.js'></script>
</body>

</html>

这就是你在浏览器中的网络组件。

Web component displayed in a browser

因为网络组件只需要HTML、CSS和JavaScript,所以它们被浏览器原生支持,并且可以与前端框架无缝连接,包括React和Vue。下面的简单代码片断显示了如何在一个用Create React App引导的简单React App中使用Web组件。为此,你需要导入你之前定义的weather-card.js文件,并将其作为一个组件使用。

import './App.css';
import './weather-card';
function App() {
  return (
  
  );
}
export default App;

网络组件的生命周期

所有组件都遵循一个生命周期,从初始化到从DOM中移除(即卸载)。方法与每个生命周期事件相关联,这样你就可以更好地控制组件。网络组件的各种生命周期事件包括。

  • 构造器。网络组件的构造函数在它被挂载之前被调用,这意味着它是在元素被附加到文档之前创建的。它用于初始化本地状态,绑定事件处理程序,并创建影子DOM。构造函数必须对super() ,以调用Web组件类所扩展的类。

  • ConnectedCallBack。当一个元素被加载(即插入DOM树)时,它被调用。它处理初始化创建DOM节点,主要用于实例化网络请求等操作。React开发者可以将其与componentDidMount

  • attributeChangedCallback。这个方法接受三个参数:name,oldValue, 和newValue 。每当组件的一个观察属性被改变时,它就被调用。属性是使用静态的observedAttributes getter来声明观察属性的。

    static get observedAttributes() {
      return ['name', '_id'];
    }
    

    每当属性名称或_id 被改变时,attributeChangedCallback 将被调用。

  • DisconnectedCallBack。当一个元素从DOM树上被移除(即解挂)时,它被调用。它等同于React的componentWillUnmount 。它被用来释放那些不会被自动收集垃圾的资源,比如取消对DOM事件的订阅,停止间隔计时器,或者取消所有注册的回调。

  • AdoptedCallback。它在每次自定义元素被移动到一个新的文档时被调用。它只在处理IFrames时出现。

模块化的开放源码

网络组件可以成为开发网络应用的一种强大方式。无论你是对JavaScript很熟悉,还是刚开始接触它,用这个伟大的开放标准创建可重复使用的代码是很容易的,无论你的目标受众使用什么浏览器。