Исходная ссылка: https://ayushgp.github.io/html-web-components-using-vanilla-js
Переводчик: Alibaba Cloud - Иешу
Веб-компонент существует уже некоторое время. Google приложил много усилий, чтобы сделать его более доступным, но его поддержка по-прежнему не оптимальна в большинстве основных браузеров, кроме Opera и Chrome.
Но с полифиллом вы теперь можете создавать свои собственные веб-компоненты, вы можете найти соответствующую поддержку здесь:www.webcomponents.org/polyfills
В этой статье я покажу, как создавать стилизованные, интерактивные и элегантно организованные теги HTML в своих собственных файлах.
представлять
Веб-компоненты — это набор API-интерфейсов веб-платформы, которые позволяют создавать новые настраиваемые, повторно используемые и инкапсулированные теги HTML для использования на обычных веб-страницах и в веб-приложениях.
Пользовательские компоненты созданы на основе стандарта веб-компонентов и могут использоваться в современных браузерах, а также с любой библиотекой JavaScript и инфраструктурой, взаимодействующей с HTML.
Функции для поддержки веб-компонентов постепенно добавляются в спецификации HTML и DOM, что позволяет веб-разработчикам легко расширять HTML новыми элементами, инкапсулирующими стили и пользовательское поведение.
Это дает возможность создавать повторно используемые компоненты, используя только чистый JS/HTML/CSS. Если HTML не соответствует требованиям, мы можем создать соответствующий веб-компонент.
Например, ваши пользовательские данные связаны с идентификатором, и вы хотите иметь компонент, который может заполнять идентификатор пользователя и получать соответствующие данные. HTML может выглядеть так:
<user-card user-id="1"></user-card>
Это самое основное приложение веб-компонента. В следующем учебном пособии основное внимание будет уделено тому, как создать этот компонент карты пользователя.
Четыре основных концепции веб-компонентов
Стандарты HTML и DOM определяют четыре новых стандарта, помогающих определять веб-компоненты. Эти стандарты следующие:
-
Пользовательские элементы (Пользовательские элементы): веб-разработчики могут создавать новые теги HTML, улучшать существующие теги HTML или повторно разрабатывать компоненты, уже созданные другими разработчиками, путем настройки элементов. Этот API является краеугольным камнем веб-компонентов.
-
HTML-шаблоны: HTML-шаблоны определяют новые элементы, описывающие подход к клиентским шаблонам на основе стандарта DOM. Шаблоны позволяют объявлять фрагменты разметки, которые можно анализировать как HTML. Эти фрагменты не будут использоваться, когда страница начнет загружаться, но будут созданы во время выполнения.
-
Shadow DOM: Shadow DOM разработан как инструмент для создания приложений на основе компонентов. Он может решить некоторые распространенные проблемы веб-разработки, такие как возможность изолировать DOM и область компонентов, а также упростить CSS и т. д.
-
Импорт HTML: Шаблоны HTML позволяют создавать новые шаблоны, аналогично импорт HTML позволяет импортировать эти шаблоны из разных файлов. Благодаря независимому компоненту управления файлами HTML он может помочь вам лучше организовать код.
Определите пользовательские элементы
Сначала нам нужно объявить класс, который определяет поведение элемента. Этот класс должен наследоватьHTMLElementклассы, но давайте пропустим эту часть и сначала обсудим методы жизненного цикла пользовательских элементов. Вы можете использовать следующие функции обратного вызова жизненного цикла:
-
connectedCallback— Запускается всякий раз, когда элемент вставляется в DOM. -
disconnectedCallback— Запускается всякий раз, когда элемент удаляется из DOM. -
attributeChangedCallback— Запускается при добавлении, удалении, обновлении или замене атрибута элемента.
существуетUserCardсоздать папкуUserCard.js:
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определение класса. Теперь доступно в нашем HTMLuser-cardэлемент тоже.
мы будем использоватьhttps://jsonplaceholder.typicode.com/API для создания нашей карты пользователя. Вот пример данных:
{
id: 1,
name: "Leanne Graham",
username: "Bret",
email: "Sincere@april.biz",
address: {
street: "Kulas Light",
suite: "Apt. 556",
city: "Gwenborough",
zipcode: "92998-3874",
geo: {
lat: "-37.3159",
lng: "81.1496"
}
},
phone: "1-770-736-8031 x56442",
website: "hildegard.org"
}
Создать шаблон
Теперь давайте создадим шаблон, который будет отображаться на экране. Создать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__приставка. В старых браузерах мы не могли использовать теневой DOM для изоляции компонентного DOM. Таким образом, мы можем избежать случайного переопределения стиля при стилизации наших компонентов.
Стиль письма
Теперь, когда мы создали шаблон для открытки, давайте украсим его с помощью CSS. Создавать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 в начало файла:
<link rel="stylesheet" href="/UserCard/UserCard.css">
Стили готовы, и мы можем продолжать улучшать функциональность наших компонентов.
connectedCallback
Теперь нам нужно определить, что происходит, когда элемент создается и добавляется в DOM. обратите внимание здесьconstructorа такжеconnectedCallbackразница методов.
constructorметод вызывается при создании экземпляра элемента, иconnectedCallbackМетод вызывается каждый раз, когда элемент вставляется в DOM.connectedCallbackМетоды полезны при выполнении кода инициализации, такого как выборка данных или рендеринг.
Советы: вUserCard.jsвверху определите константуcurrentDocument. В импортированных сценариях HTML необходимо разрешить этим сценариям манипулировать DOM импортированного шаблона. Определите это так:
const currentDocument = document.currentScript.ownerDocument;
Далее определите нашconnectedCallbackметод:
// 元素插入 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 属性
// 注意我们要像这样指定卡片:
// <user-card user-id="1"></user-card>
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);
});
}
отображать пользовательские данные
мы определилиconnectedCallbackметод и привяжите клонированный шаблон к теневому корню. Теперь нам нужно заполнить содержимое шаблона, затем вfetchЗапускается после того, как метод получает данныеrenderметод. Напишите следующееrenderа такжеtoggleCardметод.
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>
<head>
<title>Web Component</title>
</head>
<body>
<user-card user-id="1"></user-card>
<script src="https://cdnjs.cloudflare.com/ajax/libs/webcomponentsjs/1.0.14/webcomponents-hi.js"></script>
<link rel="import" href="./UserCard/UserCard.html">
</body>
</html>
Поскольку не все браузеры поддерживают веб-компоненты, нам нужно импортировать файл webcomponents.js. Обратите внимание, что мы используем кавычки HTML для импорта наших компонентов.
Чтобы запустить этот код, вам нужно создать статический файловый сервер. Если вы не знаете, как его создать, вы можете использовать что-то вродеstatic-serverилиjson-serverТакой простой статический сервис. В уроке мы устанавливаемstatic-server:
$ npm install -g static-server
Затем в каталоге вашего проекта запустите сервер с помощью следующей команды:
$ static-server
Откройте браузер и посетитеlocalhost:3000, вы можете увидеть компонент, который мы только что создали.
Секреты и уловки
В этой короткой статье я не рассказал о веб-компонентах гораздо больше, и я хотел бы кратко изложить некоторые советы и рекомендации по разработке веб-компонентов.
имя компонента
-
Имя пользовательского элемента должно содержать тире. так
<my-tabs>а также<my-amazing-website>это юридическое имя, и<foo>а также<foo_bar>нет. -
При добавлении новых тегов в HTML необходимо обеспечить прямую совместимость, и вы не можете повторно регистрировать один и тот же тег.
-
Пользовательские теги элементов не могут быть самозакрывающимися, потому что HTML позволяет самозакрывающимся только некоторым элементам. нужно написать
<app-drawer></app-drawer>Такая форма закрытого тега.
Развернуть Компоненты
Вы можете использовать наследование при создании компонентов. Например, если вы хотите создатьUserCard, вы можете создать базовую карту пользователя, а затем расширить ее до двух определенных карт пользователей. Дополнительные сведения о наследовании компонентов см.Статья веб-разработчиков Google.
Обратные вызовы жизненного цикла Функция обратного вызова жизненного цикла
Мы создали триггер, который срабатывает автоматически при добавлении элемента в DOM.connectedCallbackметод. У нас также есть элементы, которые срабатывают при удалении из DOM.disconnectedCallbackметод.attributesChangedCallback(attribute, oldval, newval)Метод будет запущен, когда мы изменим свойства пользовательского компонента.
Компонентные элементы являются экземплярами классов
Поскольку элементы компонентов являются экземплярами классов, вы можете определить общедоступные методы в этих классах. Эти общедоступные методы можно использовать, чтобы позволить другим пользовательским компонентам/скриптам взаимодействовать с этими компонентами, а не просто изменять свойства этих компонентов.
определить частные методы
Частные методы могут быть определены многими способами. Я склонен использовать (немедленно выполнять функцию), потому что их легко написать и легко понять. Например, если вы создаете компонент с очень сложными внутренними функциями, вы можете сделать это так:
(function() {
// 使用第一个self参数来定义私有函数
// 当调用这些函数时,从类中传递参数
function _privateFunc(self, otherArgs) { ... }
// 现在函数只可以在你的类的作用域中可用
class MyComponent extends HTMLElement {
...
// 定义下面这样的函数可以让你有途径和这个元素交互
doSomething() {
...
_privateFunc(this, args)
}
...
}
customElements.define('my-component', MyComponent);
})()
Замороженные классы
Чтобы предотвратить добавление новых свойств, вам нужно заморозить свой класс. Это предотвращает удаление существующих свойств класса или изменение перечисляемых, настраиваемых или записываемых свойств существующих свойств, а также изменение прототипа. Вы можете использовать следующие методы:
class MyComponent extends HTMLElement { ... }
const FrozenMyComponent = Object.freeze(MyComponent);
customElements.define('my-component', FrozenMyComponent);
Примечание. Замораживание классов не позволит вам добавлять исправления во время выполнения и затруднит отладку вашего кода.
В заключение
Этот учебник по веб-компонентам очень ограничен. Частично это можно объяснить сильным влиянием React на веб-компоненты. Я надеюсь, что эта статья дала вам достаточно информации, чтобы попытаться создать свои собственные компоненты без добавления каких-либо зависимостей. ты сможешьСпецификация API пользовательских компонентовУзнайте больше о веб-компонентах.
Вы можете прочитать учебник для второй части здесь:Создание веб-компонентов на чистом JS — часть 2!