Open WangShuXian6 opened 5 years ago
声明一个类,定义元素如何表现。这个类需要继承 HTMLElement 类
connectedCallback — 每当元素插入 DOM 时被触发。 disconnectedCallback — 每当元素从 DOM 中移除时被触发。 attributeChangedCallback — 当元素上的属性被添加、移除、更新或取代时被触发。
如果需要在元素属性变化后,触发 attributeChangedCallback()回调函数,你必须监听这个属性。 这可以通过定义observedAttributes() get函数来实现 observedAttributes()函数体内包含一个 return语句,返回一个数组,包含了需要监听的属性名称:
static get observedAttributes() { return ['disabled','icon','loading'] }
constructor(){}
>该段代码处于构造函数的上方。
***
#### user-card 元素
>在 UserCard 文件夹下创建 UserCard.js:
```ts
class UserCard extends HTMLElement {
constructor() {
super();
this.addEventListener("click", e => {
this.toggleCard();
});
}
toggleCard() {
console.log("Element was clicked!");
}
}
customElements.define("user-card", UserCard);
customElements.define('user-card', UserCard) 函数调用告知 DOM 我们已经创建了一个新的定制元素叫 user-card 它的行为被 UserCard 类定义。 现在可以在我们的 HTML 里使用 user-card 元素了。
UserCard.html
<template id="user-card-template"> <div> <h2> <span></span> ( <span></span>) </h2> <p>Website: <a></a></p> <div> <p></p> </div> <button class="card__details-btn">More Details</button> </div> </template> <script src="/UserCard/UserCard.js"></script>
在类名前加了一个 card__ 前缀,避免意外的样式覆盖 在较早版本的浏览器中,我们不能使用 shadow DOM 来隔离组件 DOM
编写样式
UserCard.css
.card__user-card-container { text-align: center; display: inline-block; border-radius: 5px; border: 1px solid grey; font-family: Helvetica; margin: 3px; width: 30%; }
.card__user-card-container:hover { box-shadow: 3px 3px 3px; }
.card__hidden-content { display: none; }
.card__details-btn { background-color: #dedede; padding: 6px; margin-bottom: 8px; }
>UserCard.html 文件的最前面引入这个 CSS 文件:
***
### 组件的功能
#### connectedCallback
>constructor 方法是元素被实例化时调用
>connectedCallback 方法是每次元素插入 DOM 时被调用。
>connectedCallback 方法在执行初始化代码时是很有用的,比如获取数据或渲染。
>在 UserCard.js 的顶部,定义一个常量 currentDocument。它在被引入的 HTML 脚本中是必要的,允许这些脚本有途径操作引入模板的 DOM。像下面这样定义:
```ts
const currentDocument = document.currentScript.ownerDocument;
定义 connectedCallback 方法 把克隆好的模板绑定到 shadow root 上
// 元素插入 DOM 时调用 connectedCallback() { const shadowRoot = this.attachShadow({ mode: "open" }); // 选取模板并且克隆它。最终将克隆后的节点添加到 shadowDOM 的根节点。
// 当前文档需要被定义从而获取引入 HTML 的 DOM 权限。 const template = currentDocument.querySelector("#user-card-template");
const instance = template.content.cloneNode(true); shadowRoot.appendChild(instance);
// 从元素中选取 user-id 属性
// 注意我们要像这样指定卡片:
//
const userId = this.getAttribute("user-id"); // 根据 user ID 获取数据,并且使用返回的数据渲染
fetch(https://jsonplaceholder.typicode.com/users/${userId}
)
.then(response => response.text())
.then(responseText => {
this.render(JSON.parse(responseText));
})
.catch(error => {
console.error(error);
});
}
***
#### 渲染用户数据
```ts
render(userData) {
// 使用操作 DOM 的 API 来填充卡片的不同区域
// 组件的所有元素都存在于 shadow dom 中,所以我们使用了 this.shadowRoot 这个属性来获取 DOM
// DOM 只可以在这个子树种被查找到
this.shadowRoot.querySelector(".card__full-name").innerHTML = userData.name;
this.shadowRoot.querySelector(".card__user-name").innerHTML =
userData.username;
this.shadowRoot.querySelector(".card__website").innerHTML = userData.website;
this.shadowRoot.querySelector(".card__address").innerHTML = `<h4>Address</h4>
${userData.address.suite}, <br />
${userData.address.street},<br />
${userData.address.city},<br />
Zipcode: ${userData.address.zipcode}`;
}
toggleCard() {
let elem = this.shadowRoot.querySelector(".card__hidden-content");
let btn = this.shadowRoot.querySelector(".card__details-btn");
btn.innerHTML =
elem.style.display == "none" ? "Less Details" : "More Details";
elem.style.display = elem.style.display == "none" ? "block" : "none";
}
既然组件已经完成,我们就可以把它用在任意项目中了。为了继续教程,我们需要创建一个 index.html 文件
<html>
Web Components
定制元素(Custom Elements):
HTML 模板(HTML Templates):
Shadow DOM:
HTML 引用(HTML Imports):