input range区域范围选择实例页面

回到相关文章 »

效果:

区域范围选择

区域单值选择

代码:

CSS代码:
:host {
    --ui-range-track-hegiht: 4px;
    --ui-range-thumb-size: 16px;
    --ui-gray: #a2a9b6;
    --ui-blue: #2a80eb;
    display: inline-block;
    position: relative;
}
:host([multiple]) {
    pointer-events: none;
}
[type="range"] {
    display: block;
    -webkit-appearance: none;
    appearance: none;
    margin: 0;
    outline: 0;
    background: none;
    width: -webkit-fill-available;
    width: fill-available;
    width: fill;
}
[type="range"] + [type="range"] {
    position: absolute;
    left: 0; top: 0; bottom: 0;
    margin: auto;
}
[type="range"]::-webkit-slider-runnable-track {
    display: flex;
    align-items: center;
    height: var(--ui-range-track-hegiht);
    border-radius: var(--ui-range-track-hegiht);
    background: linear-gradient(to right, var(--ui-gray) calc(1% * var(--from, 0)), var(--ui-blue) calc(1% * var(--from, 0)) calc(1% * var(--to, 100)), var(--ui-gray) 0%);
}
[type="range"]::-webkit-slider-thumb {
    -webkit-appearance: none;
    appearance: none;
    pointer-events: auto;
    width: var(--ui-range-thumb-size);
    height: var(--ui-range-thumb-size);
    border-radius: 50%;
    background-color: #fff;
    box-shadow: 0 1px 3px 1px rgba(0, 0, 0, .25);
    transition: border-color .15s, background-color .15s;
    cursor: pointer;
    margin-top: calc((var(--ui-range-thumb-size) - var(--ui-range-track-hegiht)) * -0.5);
}
[type="range"]::-webkit-slider-thumb:active {
    background-color: var(--ui-light,#f7f9fa);
    box-shadow: 0 0 1px 1px rgba(0, 0, 0, .25);
}
[type="range"] + [type="range"]::-webkit-slider-runnable-track {
    background: none;
}
/* Firefox */
[type="range"] {
    width: -moz-available;
}
input[type=range]::-moz-range-track {
    display: flex;
    align-items: center;
    height: var(--ui-range-track-hegiht);
    border-radius: var(--ui-range-track-hegiht);
    background: linear-gradient(to right, var(--ui-gray) calc(1% * var(--from, 0)), var(--ui-blue) calc(1% * var(--from, 0)) calc(1% * var(--to, 100)), var(--ui-gray) 0%);
}
input[type=range]::-moz-range-thumb {
    -webkit-appearance: none;
    appearance: none;
    pointer-events: auto;
    width: var(--ui-range-thumb-size);
    height: var(--ui-range-thumb-size);
    border-radius: 50%;
    background-color: #fff;
    box-shadow: 0 1px 3px 1px rgba(0, 0, 0, .25);
    transition: border-color .15s, background-color .15s;
    cursor: pointer;
    margin-top: calc((var(--ui-range-thumb-size) - var(--ui-range-track-hegiht)) * -0.5);
}
[type="range"]::-moz-range-thumb:active {
    background-color: var(--ui-light,#f7f9fa);
    box-shadow: 0 0 1px 1px rgba(0, 0, 0, .25);
}
[type="range"] + [type="range"]::-moz-range-track {
    background: none;
}
HTML代码:
<h4>区域范围选择</h4>
<ui-range min="0" max="100" value="30, 60" multiple></ui-range>
<h4>区域单值选择</h4>
<ui-range min="0" max="100" value="30"></ui-range>
                
业务JS代码:
document.querySelectorAll('ui-range').forEach(input => {
    input.addEventListener('input', function () {
        this.nextElementSibling.innerHTML = this.value;
    });
});
组件JS代码:
class uiRange extends HTMLElement {
    constructor () {
        super();
    }
    static get style () {
        return `<style>
/* 上面的CSS代码 */
</style>`;
    }
    static get observedAttributes () {
        return ['max', 'min', 'step', 'value'];
    }
    get value () {
        return this.getAttribute('value');
    }
    set value (val) {
        this.setAttribute('value', val);
    }
    get min () {
        return this.getAttribute('min') || '0';
    }
    set min (val) {
        this.setAttribute('min', val);
    }
    get max () {
        return this.getAttribute('max') || '100';
    }
    set max (val) {
        this.setAttribute('max', val);
    }
    get step () {
        return this.getAttribute('step') || '1';
    }
    set step (val) {
        this.setAttribute('step', val);
    }

    get multiple () {
        return this.hasAttribute('multiple');
    }
    set multiple (val) {
        this.toggleAttribute('multiple', val);
    }

    connectedCallback () {
        this.create();
    }
    attributeChangedCallback (name, oldValue, newValue) {
        // 略,非重点
        this.render();
    }
    create () {
        // Shadow DOM元素
        let shadow = this.attachShadow({
            mode: 'open'
        });

        // 样式
        shadow.innerHTML = uiRange.style;

        // 赋值处理
        let value = this.value || '';
        let arrValue = value.split(/,\s*|\s+/);

        if (this.multiple && arrValue.length === 1) {
            arrValue[1] = arrValue[0];
        }
        arrValue.forEach((val, index) => {
            let range = document.createElement('input');
            range.type = 'range';
            // 默认属性
            ['max', 'min', 'step'].forEach(attr => {
                if (this.hasAttribute(attr)) {
                    range[attr] = this[attr];
                }
            });
            // 赋值处理
            if (val) {
                range.value = val;
            }

            // 事件处理
            range.addEventListener('input', (event) => {
                this.dispatchEvent(new CustomEvent('input'));
            });

            // 放在Shadow DOM中
            shadow.append(range);
            // 暴露给自定义元素
            this['range' + index] = range;
        });
        
        // 事件
        this.events();
    }

    events () {
        this.addEventListener('input', _ => {
            // value值变化
            let value0 = this.range0.value;
            this.value = value0;
            if (this.multiple) {
                let value1 = this.range1.value;
                this.value = [value0, value1].map(val => {
                    return Number(val);
                }).sort(function (a, b) {
                    return a - b;
                }).join();
            }
        });
    }

    render () {
        let value = this.value;
        let arrValue = value.split(/,\s*|\s+/);
        // 百分比值确定
        let min = this.min;
        let max = this.max;
        let distance = max - min;
        let from = 0;
        let to = 100;

        if (this.multiple) {
            from = 100 * (arrValue[0] - min) / distance;            
        }
        to = 100 * ((arrValue[1] || arrValue[0]) - min) / distance;

        this.style.setProperty('--from', from);
        this.style.setProperty('--to', to);
    }
}
if (!customElements.get('ui-range')) {
    customElements.define('ui-range', uiRange);
}