Пользовательский тег выбора
Я хочу создать пользовательский тег выбора, например, и я хочу, чтобы он наследовал все атрибуты. Я старался:
document.registerElement('my-select', {
prototype: Object.create(HTMLSelectElement.prototype),
extends: 'select'
});
document.registerElement('my-option', {
prototype: Object.create(HTMLOptionElement.prototype),
extends: 'option'
});
Но, похоже, это не работает. Что я сделал не так?
2 ответа
У вас есть только абстрактный способ создания настраиваемого компонента select. Реализация будет включать создание двух прототипов, а именно, для select и option, и, наконец, подключение его к настраиваемому полю выбора, которое мы объявим на HTML-странице.
Закажите эту ссылку для демонстрации: https://jsfiddle.net/47gzo8kt/
Javascript:
var CustomizedSelectOptionPrototype = Object.create(HTMLElement.prototype);
document.registerElement('cust-select-option', { prototype: CustomizedSelectOptionPrototype});
var CustomizedSelectProto = Object.create(HTMLSelectElement.prototype);
CustomizedSelectProto.createdCallback = function() {
if (!this.getAttribute('tabindex')) {
this.setAttribute('tabindex', 0);
}
this.placeholder = document.createElement('span');
this.appendChild(this.placeholder);
var selected = this.querySelector('cust-select-option[selected]');
this.placeholder.textContent = selected ? selected.textContent : (this.getAttribute('placeholder') || '');
};
document.registerElement('cust-select', { prototype: CustomizedSelectProto, extends:"select"});
HTML:
<label>
Customized Select Box:
<select is="cust-select" placeholder="Please select an option">
<option selected value="1">English</option>
<option value="2">French</option>
<option value="3">Hindi</option>
</select>
</label>
Прошло некоторое время с тех пор, как был задан этот вопрос. Однако я столкнулся с этим, пытаясь сделать то же самое. Кажется, спецификации v0 и v1 сейчас беспорядок. Несмотря на использование того же кода для HTMLButtonElement, он бросает недопустимый конструктор в chrome, так же, как и использование HTMLSelectElement. Я начал писать это и думал, что поделюсь. Он может быть очищен и добавлено больше методов select element, но подумал, что другие могут взять его отсюда, чтобы адаптировать его к своим потребностям.
class mySelectElement extends HTMLElement {
static get observedAttributes() { return ['disabled']; }
constructor() {
super();
let shadowRoot = this.attachShadow({
mode: 'open'
}),
content = document.createElement('slot'),
options = null;
content.setAttribute('select', 'option');
shadowRoot.innerHTML = `<style>
:host([disabled]) {
background: grey;
pointer-events: none;
opacity: 0.4;
pointer-events: none;
height: 16px;
}
:host:before{
content: '';
}
:host{
contain: layout size style;
overflow: auto;
align-items:center;
background-color:rgb(255, 255, 255);
border: 1px solid black;
color:rgb(0, 0, 0);
display:inline-block;
font: 13.3333px Arial;
height:16px;
width:145px;
writing-mode:horizontal-tb;
-webkit-appearance:menulist;
-webkit-rtl-ordering:logical;
}
.hide{
display:none;
}
#options{
position: fixed;
border:1px solid blue;
}
::slotted(option){
background-color:white;
}
::slotted(:hover){
background-color: #a4d8d2;
}
</style>
<div id="options" class="hide"></div>`;
options = shadowRoot.getElementById('options');
options.appendChild(content);
this.disabled = false;
this.setAttribute('tabIndex', -1);
this.addEventListener('click', function (e) {
let target = e.target;
if (target.nodeName == 'OPTION') {
this.value = target.value;
Array.from(target.parentElement.children).forEach(x => x.removeAttribute('selected'));
target.setAttribute('selected', '');
shadowRoot.styleSheets[0].rules[1].style.cssText = "content: "
+ '"' + target.textContent + '"';
this.blur();
}
});
this.addEventListener('focus', function () {
let rect = this.getBoundingClientRect();
options.style.top = rect.bottom;
options.style.left = rect.left;
options.style.width = rect.width;
options.classList.remove('hide');
});
this.addEventListener('focusout', function () {
options.classList.add('hide');
});
this.add = function (item) {
this.appendChild(item);
if (this.value == undefined) {
this.value = content.assignedNodes()[0].value;
content.assignedNodes()[0].setAttribute('selected', '');
shadowRoot.styleSheets[0].rules[1].style.cssText = "content: " +
'"' + content.assignedNodes()[0].textContent + '"';
}
}
this.item = function (i) {
return content.assignedNodes()[i];
}
this.namedItem = function (val) {
return content.assignedNodes().find(x => x.value == val);
}
this.remove = function (i) {
return content.assignedNodes()[i].remove();
}
}
attributeChangedCallback(attributeName, oldValue, newValue, namespace) {
if (attributeName == 'disabled') {
if (newValue = '')
this.disabled = true;
else if (newValue == null)
this.disabled = false;
}
}
}
customElements.define('my-select', mySelectElement);
var _select = customElements.get('my-select');
var select = new _select;
document.body.appendChild(select);
for (let i = 0; i < 10; i++) {
let option = document.createElement('option');
option.innerHTML = 'hello_' + i;
option.value = 'h' + i;
select.add(option);
}