在前端开发中,我们经常需要创建各种各样的输入框组件,如表单输入、搜索框等等。这些输入框通常都需要一些基本的功能,如输入数据校验、错误提示、placeholder 等等。为了提高代码的重用性和可维护性,我们可以使用 Custom Elements 来创建一个可重用的输入框组件。
Custom Elements 简介
Custom Elements 是一个原生 Web API,它允许我们创建自定义 HTML 元素。使用 Custom Elements,我们可以定义一个自定义元素并注册到文档中,从而可以在 HTML 中直接使用该自定义元素。
创建一个可重用的输入框组件
接下来,我们将使用 Custom Elements 来创建一个可重用的输入框组件,具有以下功能:
- 输入数据校验
- 错误提示
- placeholder
定义 Custom Element
首先,我们需要定义一个 Custom Element,我们可以为该元素指定一个名称,例如 my-input。然后,我们可以使用 class 继承 HTMLElement 来定义自定义元素的行为。
class MyInput extends HTMLElement {
// ...
}
customElements.define('my-input', MyInput);Shadow DOM
在 Custom Element 中使用 Shadow DOM 可以作为一种隔离机制来保护我们的 CSS 样式和 JavaScript 代码。我们可以使用 attachShadow 方法创建 Shadow DOM,并将 Shadow DOM 附加到 Custom Element 中。
// www.javascriptcn.com code example
class MyInput extends HTMLElement {
constructor() {
super();
const template = document.createElement('template');
template.innerHTML = `
<style>
:host {
display: block;
}
input {
border: 2px solid #ccc;
border-radius: 5px;
font-size: 16px;
padding: 10px;
width: 100%;
}
input:focus {
border-color: blue;
outline: none;
}
.error {
color: red;
font-size: 12px;
margin-top: 5px;
}
</style>
<input />
<div class="error"></div>
`;
const shadowRoot = this.attachShadow({ mode: 'open' });
shadowRoot.appendChild(template.content.cloneNode(true));
}
}在上面的例子中,我们定义了 input、error 这两个元素,并为 Custom Element 添加了 CSS 样式。我们还可以在 constructor 中添加其他行为,例如添加事件监听器。
输入数据校验和错误提示
我们可以使用 attributeChangedCallback 方法来监听 Custom Element 属性的变化。当我们的输入框的值变化时,我们可以根据输入的内容校验数据,并在错误时显示错误信息。
// www.javascriptcn.com code example
class MyInput extends HTMLElement {
set value(val) {
this.setAttribute('value', val);
}
get value() {
return this.shadowRoot.querySelector('input').value;
}
static get observedAttributes() {
return ['required', 'pattern', 'error-message'];
}
attributeChangedCallback(name, oldValue, newValue) {
const input = this.shadowRoot.querySelector('input');
const error = this.shadowRoot.querySelector('.error');
switch (name) {
case 'required':
input.required = !!newValue;
break;
case 'pattern':
input.pattern = newValue;
break;
case 'error-message':
error.innerHTML = newValue;
break;
default:
break;
}
}
constructor() {
super();
const template = document.createElement('template');
// ...
const shadowRoot = this.attachShadow({ mode: 'open' });
shadowRoot.appendChild(template.content.cloneNode(true));
const input = shadowRoot.querySelector('input');
input.addEventListener('input', () => {
if (input.checkValidity()) {
error.innerHTML = '';
} else {
error.innerHTML = this.getAttribute('error-message') || '输入有误';
}
});
}
}
customElements.define('my-input', MyInput);在上面的例子中,我们添加了 set value 和 get value 方法,可以方便地读取和设置输入框的值。同时,在 attributeChangedCallback 中,我们监听了 required、pattern 和 error-message 三个属性的变化。当输入框的内容变化时,我们在事件监听器中对数据进行校验,并在输入有误时显示错误信息。
Placeholder
我们还可以通过在 Custom Element 中添加 placeholder 属性来实现占位符效果。
// www.javascriptcn.com code example
class MyInput extends HTMLElement {
// ...
static get observedAttributes() {
return ['required', 'pattern', 'error-message', 'placeholder'];
}
attributeChangedCallback(name, oldValue, newValue) {
const input = this.shadowRoot.querySelector('input');
const error = this.shadowRoot.querySelector('.error');
switch (name) {
case 'required':
input.required = !!newValue;
break;
case 'pattern':
input.pattern = newValue;
break;
case 'error-message':
error.innerHTML = newValue;
break;
case 'placeholder':
input.placeholder = newValue;
break;
default:
break;
}
}
constructor() {
super();
const template = document.createElement('template');
// ...
const shadowRoot = this.attachShadow({ mode: 'open' });
shadowRoot.appendChild(template.content.cloneNode(true));
const input = shadowRoot.querySelector('input');
input.addEventListener('input', () => {
// ...
});
if (this.hasAttribute('placeholder')) {
input.placeholder = this.getAttribute('placeholder');
}
}
}
customElements.define('my-input', MyInput);在上面的例子中,我们添加了 placeholder 属性,并在 attributeChangedCallback 中进行处理,同时在 constructor 中初始化占位符。
示例代码
最后,我们来看一下完整的示例。下面是一个 my-input 的使用例子,该输入框设置了输入格式校验、错误提示和 placeholder。
<my-input
required
pattern="[A-Za-z]{3}"
error-message="只能输入 3 个字母"
placeholder="请输入三个字母"
></my-input>// www.javascriptcn.com code example
class MyInput extends HTMLElement {
set value(val) {
this.setAttribute('value', val);
}
get value() {
return this.shadowRoot.querySelector('input').value;
}
static get observedAttributes() {
return ['required', 'pattern', 'error-message', 'placeholder'];
}
attributeChangedCallback(name, oldValue, newValue) {
const input = this.shadowRoot.querySelector('input');
const error = this.shadowRoot.querySelector('.error');
switch (name) {
case 'required':
input.required = !!newValue;
break;
case 'pattern':
input.pattern = newValue;
break;
case 'error-message':
error.innerHTML = newValue;
break;
case 'placeholder':
input.placeholder = newValue;
break;
default:
break;
}
}
constructor() {
super();
const template = document.createElement('template');
template.innerHTML = `
<style>
:host {
display: block;
}
input {
border: 2px solid #ccc;
border-radius: 5px;
font-size: 16px;
padding: 10px;
width: 100%;
}
input:focus {
border-color: blue;
outline: none;
}
.error {
color: red;
font-size: 12px;
margin-top: 5px;
}
</style>
<input />
<div class="error"></div>
`;
const shadowRoot = this.attachShadow({ mode: 'open' });
shadowRoot.appendChild(template.content.cloneNode(true));
const input = shadowRoot.querySelector('input');
input.addEventListener('input', () => {
if (input.checkValidity()) {
error.innerHTML = '';
} else {
error.innerHTML = this.getAttribute('error-message') || '输入有误';
}
});
if (this.hasAttribute('placeholder')) {
input.placeholder = this.getAttribute('placeholder');
}
}
}
customElements.define('my-input', MyInput);这样,我们就成功地使用 Custom Elements 创建了一个可重用的输入框组件。使用 Custom Elements,我们可以封装一些常用的功能,从而极大地提高代码的重用性和可维护性,同时使代码更加清晰和易读,是一个很好的 Web 技术。
来源:JavaScript中文网 ,转载请注明来源 https://www.javascriptcn.com/post/67cfd9a5e46428fe9ec00975