简体   繁体   中英

Custom select tag

I want to create a custom select tag for example and I want it to inherit all of attributes. I tried:

document.registerElement('my-select', {
    prototype: Object.create(HTMLSelectElement.prototype),
    extends: 'select'
});

document.registerElement('my-option', {
    prototype: Object.create(HTMLOptionElement.prototype),
    extends: 'option'
});

But it seems it doesn't work. What have I done wrong?

You have only provide the abstract way of building a customized select component, The implementation will include creating two prototypes namely for select and option and finally hooking it up with the customized select box which we will be declaring in the HTML page.

Checkout this fiddle link for a demo : 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>

It's been awhile since this question was asked. However I came across it looking to do the same thing. It seems the v0 and v1 specs are a mess right now. Despite using the same code for HTMLButtonElement , it's throwing illegal constructor in chrome, same as using HTMLSelectElement. I've started to write this and thought I would share. It could be cleaned up and more of the select element methods added but figured others could take it from here to tailor it to their needs.

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);
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM