Open wingmeng opened 5 years ago
.slider { padding: 5px 0; position: relative; margin: 30px 10%; --percent: 0; } .slider-track { display: block; width: 100%; height: 6px; background-color: lightgray; border: 0; padding: 0; } .slider-track::before { content: ''; display: block; height: 100%; background-color: skyblue; width: calc(1% * var(--percent)); } .slider-thumb { position: absolute; width: 16px; height: 16px; border: 0; padding: 0; background: #fff; box-shadow: 0 0 0 1px skyblue; border-radius: 50%; left: calc(1% * var(--percent)); top: 0; margin: auto -8px; }
> 在线 DEMO <
let myslider1 = new Slider({ el: '#box' }); // 指定容器 new Slider({ value: 50 }); // 缺省赋值 new Slider(); // 无参数(插入到 body 标签最后,赋值为 0) myslider1.val(value); // js 动态赋值
class Slider { constructor(opts = {}) { this.el = opts.el; this.value = opts.value || 0; this.slider = null; this.render(); this.bindEvt(); return { // 赋值方法 val: (value) => { this.val(value); } } } // 渲染 DOM render() { const container = document.querySelector(this.el); const slider = document.createElement('div'); this.slider = slider; // 有缺省值则赋值 if (this.value) { this.val(this.value); } slider.className = 'slider'; slider.innerHTML = ( // 轨道无需获取焦点 `<button class="slider-track" tabindex="-1"></button> <button class="slider-thumb"></button>` ); if (container) { container.appendChild(slider); } else { // 若未指定容器,则在 body 标签最后插入 DOM 结构 document.body.appendChild(slider); } } // 绑定事件 bindEvt() { const { slider } = this; const slider_track = slider.querySelector('.slider-track'); const slider_thumb = slider.querySelector('.slider-thumb'); let readyMove = false; const startHandle = e => { if (e.target === slider_thumb) { e.stopPropagation(); readyMove = true; } }; const moveHandle = e => { if (readyMove) { this.computeVal(e); } }; const endHandle = () => readyMove = false; // 点击监听 slider.addEventListener('click', e => { // 点击轨道 if (e.target === slider_track) { this.computeVal(e); } }, false); // 键盘监听 slider.addEventListener('keydown', e => { // 滑块获得焦点 if (document.activeElement === slider_thumb) { let value = this.val(); switch(e.keyCode) { case 37: // 左箭头 value--; break; case 39: // 右箭头 value++; break; } this.val(value); } }, false); // 开始拖动 slider.addEventListener('touchstart', startHandle); slider.addEventListener('mousedown', startHandle); // 拖动中 window.addEventListener('touchmove', moveHandle); window.addEventListener('mousemove', moveHandle); // 拖动结束 window.addEventListener('touchend', endHandle); window.addEventListener('mouseup', endHandle); } // 计算当前值 computeVal(e) { const { width, left } = this.slider.getBoundingClientRect(); let posX = e.pageX; if (e.touches) { // 兼容移动端 posX = e.touches[0].pageX; } this.val((posX - left) / width * 100); } // 赋值 & 取值 val(value) { if (typeof value === 'undefined') { // 返回当前 slider 的 percent 值 return this.slider.style.getPropertyValue('--percent').trim() || 0; } if (isNaN(value)) { // 过滤非法字符 return; } // 边界处理 if (value < 0) { value = 0; } else if (value > 100) { value = 100; } this.slider.style.setProperty('--percent', value); } }
优秀
优秀、良好、一般、差劲
pageX
getBoundingClientRect
getPropertyValue
setProperty
题目:
我的答案:
> 在线 DEMO <
使用方式示例
已封装的 Slider 组件