quiz
quiz copied to clipboard
DOM基础测试30
本期小测题目如下:
.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;
}
<div class="slider">
<button class="slider-track"></button>
<button class="slider-thumb"></button>
</div>
大家提交回答的时候,注意缩进距离,起始位置从左边缘开始;另外,github自带代码高亮,所以请使用下面示意的格式。
```js // 你的JS代码写在这里 ```
另外,务必提供在线demo,方便验证与评分。jsbin.com jsfiddle.net codepen.io或者国内类似站点都可以,也可以使用github page。
没有可访问demo积分-1分哟。
-----其他-----
本期小测答疑直播4月13日周六上午10:00,预计半小时左右。直播地址:https://live.bilibili.com/21193211
首位答题者会额外2积分。
感谢您的参与!
赶了个早。 demo
<h3>slider1</h3>
<div class="slider" tabindex="0" style="--percent:50">
<button class="slider-track" tabindex="-1"></button>
<button class="slider-thumb" tabindex="-1" data-title="50"></button>
</div>
<h3>slider2</h3>
<div class="slider" tabindex="0" style="--percent:20">
<button class="slider-track" tabindex="-1"></button>
<button class="slider-thumb" tabindex="-1" data-title="20"></button>
</div>
/**借助之前的css-tips**/
.slider-thumb[data-title]:before{
counter-reset: value var(--percent);
content: counter(value);
}
html:hover .slider-thumb[data-title]:active:before,
html:hover .slider-thumb[data-title]:active:after,
.slider:focus .slider-thumb[data-title]:before,
.slider:focus .slider-thumb[data-title]:after {
visibility: visible;
transform: translate(-50%, -10px);
opacity: 1;
}
//可能没看清题意,需要生成dom结构,现补一个(不过比较简单的结构平时都直接写在页面了)
var oSlider = document.createElement('div');
oSlider.className = 'slider';
oSlider.innerHTML = '<button class="slider-track"></button><button class="slider-thumb"></button>';
document.body.appendChild(oSlider);
oSlider.style.setProperty('--percent', 50);
;(function(){
var slider = document.querySelectorAll('.slider');
slider.forEach(function(el){
el.addEventListener('mousedown',function(ev){
const { left,width } = el.getBoundingClientRect();
const percent = (ev.pageX-left)/width*100;
render(el,percent);
document.onmousemove = function(ev){
const percent = (ev.pageX-left)/width*100;
render(el,percent);
}
document.onmouseup = function(ev){
document.onmousemove = null;
}
})
el.addEventListener('keydown',function(ev){
el.focus();
let percent = Number(getComputedStyle(el).getPropertyValue('--percent'));
switch (ev.keyCode) {
case 37:
percent -= 1;
break;
case 39:
percent += 1;
break;
default:
break;
}
render(el,percent);
})
})
function render(el,percent){
percent = Math.min( Math.max(0,percent),100);
el.style.setProperty('--percent', parseInt(percent,10));
}
})()
- 支持 PC 端和移动端;
- 支持缺省赋值(第 2 题);
- 支持键盘操作;
- 可使用 js 动态赋值(第 2 题);
- 可指定渲染容器,默认渲染到 body 标签最后(第 1 题);
- 支持点击“轨道”赋值定位(第 3 题);
- 支持滑块拖动赋值(第 4 题)。
使用方式示例
let myslider1 = new Slider({ el: '#box' }); // 指定容器
new Slider({ value: 50 }); // 缺省赋值
new Slider(); // 无参数(插入到 body 标签最后,赋值为 0)
myslider1.val(value); // js 动态赋值
已封装的 Slider 组件
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);
}
}
var $ = q => document.querySelector(q)
var node = document.createElement('DIV')
node.setAttribute('class', 'slider')
node.innerHTML = ` <button class="slider-track"></button>
<button class="slider-thumb"></button>`
$('body').appendChild(node)
setTimeout(() => {
// window.addEventListener('click', e => e.stopPropagation())
$('.slider-thumb').addEventListener('click', e => e.stopPropagation())
$('.slider').style.setProperty('--percent', 50)
document.querySelector('.slider').addEventListener('click', function(e) {
console.log(e.pageX, e.clientX, e.offsetX)
this.style.setProperty(
'--percent',
(e.offsetX / this.clientWidth) * 100,
)
})
const dragHandle = function(e1) {
var Length = e1.clientX - $('.slider').getBoundingClientRect().x
console.log(e1.clientX, $('.slider'))
Length <= 0 && $('.slider').style.setProperty('--percent', 0)
Length >= $('.slider').clientWidth &&
$('.slider').style.setProperty('--percent', 100)
Length >= 0 &&
Length <= $('.slider').clientWidth &&
$('.slider').style.setProperty(
'--percent',
(Length / $('.slider').clientWidth) * 100,
)
}
$('.slider').addEventListener('mousedown', function(e) {
console.log('down')
document.addEventListener('mousemove', dragHandle)
})
document.addEventListener('mouseup', function(e) {
document.removeEventListener('mousemove', dragHandle)
})
}, 200)
class Slider{
constructor(v=0){
this.isDraging = false
this.init()
this.bindClick()
this.bindDrag()
this.setPercent(v)
}
init(){
let slider = document.createElement('div')
slider.className = 'slider'
slider.innerHTML = `<button class="slider-track"></button><button class="slider-thumb"></button>`
document.body.appendChild(slider)
this.slider = slider
}
bindClick(){
this.slider.addEventListener('click', e => {
if (this.isDraging) return
let percent = Math.round(e.offsetX / this.slider.offsetWidth * 100)
this.setPercent(percent)
}, false)
}
bindDrag(){
let start = 0
let x = 0
let thumb = this.slider.getElementsByClassName('slider-thumb')[0]
let max = this.slider.offsetWidth
function down(e){
if (e.target.className === 'slider-thumb'){
e.preventDefault()
this.isDraging = true
start = e.pageX
x = this.getPercent()
}
}
function move(e){
if (!this.isDraging) return
e.preventDefault()
let now = Math.round((e.pageX - start) / max * 100) + x
if (now < 0 ) now = 0
else if (now > 100) now = 100
this.setPercent(now)
}
function up(e){
if (!this.isDraging) return
// 在下次事件循环解锁click事件
setTimeout(() => {
this.isDraging = false
}, 0)
}
window.addEventListener('mousedown', down.bind(this), false)
window.addEventListener('mousemove', move.bind(this), false)
window.addEventListener('mouseup', up.bind(this), false)
}
setPercent(v=0){
if (typeof v !== 'number' || v > 100 || v < 0) throw new TypeError('param error')
this.slider.style.setProperty('--percent', v)
}
getPercent(){
return +window.getComputedStyle(this.slider, null).getPropertyValue('--percent')
}
}
let s = new Slider(50)
<div class="slider" data-percent="10">
<button class="slider-track"></button>
<button class="slider-thumb"></button>
</div>
<div class="slider" data-percent="30">
<button class="slider-track"></button>
<button class="slider-thumb"></button>
</div>
<div class="slider" data-percent="40">
<button class="slider-track"></button>
<button class="slider-thumb"></button>
</div>
(function(){
let aSlider = document.querySelectorAll(".slider");
[...aSlider].forEach((item, index) => {
let initPercent = item.dataset.percent;
setPercent(item, initPercent);
item.onmousedown = function(e){
let {left, width} = item.getBoundingClientRect();
let percent = (e.pageX - left) / width * 100;
setPercent(item, percent);
document.onmousemove = function(e){
let percent = (e.pageX - left) / width * 100;
setPercent(item, percent);
};
document.onmouseup = function(e){
document.onmousemove = document.onmouseup = null;
};
}
});
function setPercent(el, percent){
percent = Math.min(Math.max(0, percent), 100);
el.style.setProperty("--percent", percent);
}
})()
let silderDom = document.createElement('div');
div.setAttribute('class', 'slider');
div.style.setProperty('--percent', '50');
let trackDom = document.createElement('button');
let thumbDom = document.createElement('button');
button1.setAttribute('class', 'slider-track');
button2.setAttribute('class', 'slider-thumb');
div.appendChild(button1);
div.appendChild(button2);
document.body.appendChild(div);
trackDom.addEventListener('click', function(event) {
let { width: trackDomWidth, left: trackDomLeft } = trackDom.getBoundingClientRect();
let { offsetX } = event;
let percent = offsetX / trackDomWidth;
silderDom.style.setProperty('--percent', percent * 100);
});
let startX;
let thumbDomMove = function(event) {
let { width: trackDomWidth, left: trackDomLeft } = trackDom.getBoundingClientRect();
let endX = Math.min(Math.max(event.pageX, trackDomLeft), trackDomLeft + trackDomWidth);
let percent = Number(silderDom.style.getPropertyValue('--percent'));
let newPercent = percent + (endX - startX) / trackDomWidth * 100;
newPercent = Math.min(Math.max(newPercent, 0), 100);
silderDom.style.setProperty('--percent', newPercent);
startX = endX;
};
document.addEventListener('mousedown', function(event) {
let target = event.target;
if (target !== thumbDom) return;
startX = event.pageX;
document.addEventListener('mousemove', thumbDomMove);
});
document.addEventListener('mouseup', function() {
document.removeEventListener('mousemove', thumbDomMove);
});
(function(window, document) {
// 第一题
var body = document.body;
var slider = createElement("div", "slider");
var track = createElement("div", "slider-track");
var thumb = createElement("div", "slider-thumb");
slider.appendChild(track).appendChild(thumb);
body.appendChild(slider);
// 第二题
slider.style.setProperty("--percent", 50);
// 第三题, 第四题
var isTouch = "ontouchstart" in window;
var mouseDownEvent = isTouch ? "touchstart" : "mousedown";
var mouseMoveEvent = isTouch ? "touchmove" : "mousemove";
var mouseUpEvent = isTouch ? "touchend" : "mouseup";
var sliderWidth;
slider.addEventListener(
mouseDownEvent,
function(e) {
var target = e.target || srcElement;
var className = target.className;
sliderWidth = slider.offsetWidth;
switch (className) {
// 第三题
case "slider-track":
mouseMove(e);
break;
// 第四题
case "slider-thumb":
// 使用window绑定事件,因为鼠标离开后有问题
document.addEventListener(mouseMoveEvent, mouseMove);
document.addEventListener(mouseUpEvent, mouseUp);
break;
default:
console.log(e);
}
},
false
);
// 滑块移动到指定位置
function mouseMove(e) {
var pos = isTouch ? e.touches[0].clientX : e.clientX;
setPercentByPosition(pos);
}
// 鼠标释放时,解除绑定事件
function mouseUp(e) {
document.removeEventListener(mouseMoveEvent, mouseMove);
document.removeEventListener(mouseUpEvent, mouseUp);
}
// 根据鼠标位置设置百分比
function setPercentByPosition(pos) {
var distance = pos - slider.getBoundingClientRect().left;
var percent = ~~(100 * distance / sliderWidth);
slider.style.setProperty(
"--percent",
percent > 0 ? (percent < 100 ? percent : 100) : 0
);
}
// 创建带class的元素
function createElement(tagName, className) {
var tag = document.createElement(tagName);
tag.className = className;
return tag;
}
})(window, document);
>>demo<< 试着渲染1w个slider,发现chrome开控制台就会跳帧,firefox就不会...
var newEl=(tag,className)=>{
var ele=document.createElement(tag)
ele.className=className
return ele
}
var setStylePercent=function(number){
number=number>1&&1||number<0&&'0'||number.toFixed(4)
this.style.setProperty('--percent',number*1e2)
}
var Slider=(initPer)=>{
var eSlider=newEl('div','slider')
,eTrack=newEl('button','slider-track')
,eThumb=newEl('button','slider-thumb')
eSlider.append(eTrack,eThumb)
setStylePercent.call(eSlider,initPer)
return eSlider
}
document.addEventListener('click',function(event){
if(event.target.className=='slider-track'){
eSlider=event.target.parentElement
setStylePercent.call(eSlider,event.offsetX/eSlider.clientWidth)
eSlider=null
}
})
for(evt of [{xstart:'touchstart',xmove:'touchmove',xend:'touchend'},
{xstart:'mousedown',xmove:'mousemove',xend:'mouseup'}])
document.addEventListener(evt.xstart,function(event){
if(event.target.className=='slider-thumb'){
var eSlider=event.target.parentElement
var {width,left}=eSlider.getBoundingClientRect()
var moveFunc=function(event){
setStylePercent.call(eSlider,((event.touches&&event.touches[0]||event).pageX-left)/width)
}
document.addEventListener(evt.xmove,moveFunc)
document.addEventListener(evt.xend,()=>{
document.removeEventListener(evt.xmove,moveFunc)
})
}
})
window.addEventListener('DOMContentLoaded',() => {
var a=document.createDocumentFragment()
for(var i=0;i<1e4;i++)
a.appendChild(Slider(.5))
document.body.append(a)
})
let slider = document.createElement('div')
slider.setAttribute('class', 'slider')
slider.innerHTML =
`
<button class="slider-track"></button>
<button class="slider-thumb"></button>
`
document.body.appendChild(slider)
slider.style.setProperty('--percent', 50)
const {
left,
width
} = slider.getBoundingClientRect()
// 鼠标按下时,判断target是否为thumb元素
let dragging = false
let thumb = slider.querySelector('.slider-thumb')
slider.addEventListener('click', (e) => {
// 避免其click事件与子元素mousedown事件一起发送时,出现滑块微小移动现象
// if (e.target === thumb) return
if (dragging) {
dragging = false
return
}
slider.style.setProperty('--percent', (e.pageX - left) / width * 100)
})
let fnMove = (e) => {
let diff = e.pageX - left
let sMoveLength = Math.min(Math.max(0, diff), width)
slider.style.setProperty('--percent', sMoveLength / width * 100)
}
thumb.addEventListener('mousedown', (e) => {
dragging = true
window.addEventListener('mousemove', fnMove)
})
window.addEventListener('mouseup', (e) => {
window.removeEventListener('mousemove', fnMove)
})
// 1、
var oFragment = document.createDocumentFragment('div')
var div = document.createElement('div')
div.className = 'slider';
div.innerHTML = '<button class="slider-track"></button><button class="slider-thumb"></button>'
oFragment.appendChild(div)
document.body.appendChild(oFragment)
var slider = document.querySelector('.slider')
var trackWidth = parseFloat(window.getComputedStyle(slider).width)
var trackLeft = slider.getBoundingClientRect().left
var thumb = document.querySelector('.slider-thumb')
var isMove = false
function setTrackPos(percent){
slider.style.setProperty('--percent',percent)
}
// 2、
setTrackPos('50')
// 3~4
slider.addEventListener('mousedown', function(event){
event.preventDefault()
if(event.target === thumb){
event.stopPropagation()
isMove = true
}else{
var percent = (event.offsetX/trackWidth) * 100
setTrackPos(percent)
}
})
window.addEventListener('mousemove', function(event){
if(isMove){
var moveX = event.pageX-trackLeft
if(moveX >= 0 && moveX <= trackWidth){
var percent = (moveX/trackWidth) * 100
setTrackPos(percent)
}
}
})
window.addEventListener('mouseup', function(event){
isMove = false
})
class Slider {
constructor() {
this.init();
this.setPercent(66);
this.touchHandler();
}
init() {
var body = document.getElementsByTagName('body')[0];
var ele = document.createElement('div');
ele.setAttribute('class', 'slider');
ele.innerHTML = `<button class="slider-track"></button><button class="slider-thumb"></button><div id="percent"></div>`;
body.appendChild(ele);
this.slider = document.getElementsByClassName('slider')[0];
this.thumb = document.getElementsByClassName('slider-thumb')[0];
this.width = this.slider.offsetWidth;
}
getPercent() {
return getComputedStyle(this.slider).getPropertyValue('--percent');
}
setPercent(percent) {
var element = document.getElementById('percent');
this.slider.style.setProperty('--percent', percent);
element.innerHTML = percent;
}
touchHandler() {
function move(e) {
let { left } = this.slider.getBoundingClientRect();
this.setPercent(Math.round((e.pageX - left) / this.width * 100));
}
this.slider.onmousedown = function (e) {
move.call(this, e);
if (e.target !== this.thumb) return;
this.slider.onmousemove = move.bind(this);
this.slider.onmouseup = function () {
this.slider.onmousemove = null;
}.bind(this)
}.bind(this)
}
}
var test = new Slider();
听完讲解之后修正:
(function() {
// 题一
let body = document.body;
let $slider = document.createElement("div");
$slider.setAttribute("class", "slider");
let $ele_1 = document.createElement("button");
$ele_1.setAttribute("class", "slider-track");
let $ele_2 = document.createElement("button");
$ele_2.setAttribute("class", "slider-thumb");
body.appendChild($slider);
$slider.appendChild($ele_1);
$slider.appendChild($ele_2);
// 题二
let $slider_styles = getComputedStyle($slider);
$slider.style.setProperty("--percent", 50);
// 题三
$ele_1.addEventListener("click", function(e) {
const { width } = $slider.getBoundingClientRect();
const { offsetX } = e;
const percent = offsetX / width;
$slider.style.setProperty("--percent", percent * 100);
});
// 题四
let startX;
let moveFun = function(event) {
const { width } = $slider.getBoundingClientRect();
let percent = $slider_styles.getPropertyValue("--percent").trim();
let currentX = event.pageX;
let newPercent = Number(percent) + ((currentX - startX) / width) * 100;
newPercent = Math.min(Math.max(0, newPercent), 100);
$slider.style.setProperty("--percent", newPercent);
startX = currentX;
};
document.addEventListener("mousedown", function(e) {
if (e.target !== $ele_2) {
return;
}
startX = e.pageX;
document.addEventListener("mousemove", moveFun);
});
document.addEventListener("mouseup", function(e) {
document.removeEventListener("mousemove", moveFun);
});
})();
题一
let slider = document.createElement('div')
let sliderTrack = document.createElement('button')
let sliderThumb = document.createElement('button')
slider.classList.add('slider')
sliderTrack.classList.add('slider-track')
sliderThumb.classList.add('slider-thumb')
slider.appendChild(sliderTrack)
slider.appendChild(sliderThumb)
document.body.appendChild(slider)
题二
let percent = 50
slider.style.setProperty('--percent', percent)
题三
sliderTrack.addEventListener('click', function(e){
percent = e.offsetX / sliderTrack.offsetWidth * 100
slider.style.setProperty('--percent', percent)
})
题四
function thumbMove (e) {console.log(e)
let currentPx = percent * sliderTrack.offsetWidth / 100
let newPx = currentPx + e.movementX
percent = newPx / sliderTrack.offsetWidth * 100
percent < 0 && (percent = 0)
percent > 100 && (percent = 100)
slider.style.setProperty('--percent', percent)
}
sliderThumb.addEventListener('mousedown',function(e){
document.addEventListener('mousemove', thumbMove)
})
document.addEventListener('mouseup', () =>{
document.removeEventListener('mousemove', thumbMove)
sliderThumb.blur()
})
// 第一题
function appendDOM(el) {
const node = document.createElement('div')
node.className = 'slider'
node.innerHTML =
'<button class="slider-track"></button><button class="slider-thumb"></button>'
if (el) {
document.querySelector(el).appendChild(node)
} else {
document.querySelector('body').appendChild(node)
}
return node
}
const element = appendDOM()
// 第二题
function setPercent(el, val) {
el.style.setProperty('--percent', Math.min(100, Math.max(0, val)))
}
function setPercent50() {
setPercent(element, 50)
}
// 第三题
function addClick(el) {
const handleClick = e => {
const rect = el.getBoundingClientRect()
let offsetWidth = ((e.clientX - rect.left) / rect.width) * 100
setPercent(el, offsetWidth)
}
el.addEventListener('click', handleClick)
}
addClick(element)
// 第四题
function addDrag(el) {
let status = false // 是否可拖动
let startX = 0 // 记录最开始点击的X坐标
let left = 0 // 记录当前已经移动的距离
const getPercent = el => {
return +window
.getComputedStyle(el, null)
.getPropertyValue('--percent')
}
const handleStart = e => {
if (e.target.className.indexOf('slider-thumb') > -1) {
status = true
startX = e.clientX || e.touches[0].pageX
left = getPercent(el)
}
}
const handleMove = e => {
if (status) {
const rect = el.getBoundingClientRect()
let endX = e.clientX || e.touches[0].pageX
let offsetWidth = ((endX - startX) / rect.width) * 100 + left
setPercent(el, offsetWidth)
}
}
const handleEnd = e => {
if (status) {
status = false
}
}
// pc端
el.addEventListener('mousedown', handleStart)
document.addEventListener('mousemove', handleMove)
document.addEventListener('mouseup', handleEnd)
// 移动端
el.addEventListener('touchstart', handleStart)
document.addEventListener('touchmove', handleMove)
document.addEventListener('touchend', handleEnd)
}
addDrag(element)
Demo
https://codepen.io/crazyboy/pen/pBPKye
(function () {
function createElement(type, className) {
var ele = document.createElement(type);
ele.className = className;
return ele;
}
function addHandler(element, type, handler) {
if (element.addEventListener) {
element.addEventListener(type, handler);
} else if (element.attachEvent) {
element.attachEvent('on' + type, handler);
} else {
element['on' + type] = handler;
}
}
function getOffsetLeft(ele) {
var eleLeft = 0;
do {
eleLeft += ele.offsetLeft;
ele = ele.offsetParent;
} while (ele);
return eleLeft;
}
function setPercent(event) {
var track = document.querySelector('.slider-track');
var eventX = event.type.slice(0, 5) === 'touch' ? event.targetTouches[0].clientX : event.clientX;
var percent = ((eventX - getOffsetLeft(track)) * 100 / track.offsetWidth).toFixed(2);
if (0 <= percent && percent <= 100 ) {
document.querySelector('.slider').style.setProperty('--percent', percent);
}
}
var sliderElement = createElement('div', 'slider');
var trackElement = createElement('button', 'slider-track');
var thumbElement = createElement('button', 'slider-thumb');
document.body.appendChild(sliderElement);
sliderElement.appendChild(trackElement);
sliderElement.appendChild(thumbElement);
thumbElement.setAttribute('draggable', true);
addHandler(trackElement, 'click', setPercent);
addHandler(thumbElement, 'drag', setPercent);
addHandler(thumbElement, 'touchmove', setPercent);
})();
let sliderDom = document.createElement('div');
let slideTrackDom = document.createElement('div');
let sliderThumbDom = document.createElement('div');
sliderDom.className = 'slider';
slideTrackDom.className = 'slider-track';
sliderThumbDom.className = 'slider-thumb';
sliderDom.append(slideTrackDom);
sliderDom.append(sliderThumbDom);
document.body.append(sliderDom);
let slider = document.getElementsByClassName('slider')[0];
let sliderThumb = document.getElementsByClassName('slider-thumb')[0];
let sliderTrack = document.getElementsByClassName('slider-track')[0];
let maxX = getCssValue(slider, 'width');
setCssValue(slider, '--percent', 50);
function getCssValue(context, cssName) {
let value = getComputedStyle(context).getPropertyValue(cssName);
if (value.indexOf('px')) {
return Number(value.slice(0, -2))
} else {
return value;
}
}
function setCssValue(context, cssName, cssValue) {
context.style.setProperty(cssName, cssValue);
}
function setPercentNum(percent) {
percentNum.innerHTML = Math.ceil(percent).toFixed(0) + '%';
}
function down(e) {
e = e || window.event;
this.left = getCssValue(sliderThumb, 'left');
this.startX = e.pageX;
this._MOVE = move.bind(this);
this._UP = up.bind(this);
if (document.addEventListener) {
document.addEventListener('mousemove', this._MOVE);
document.addEventListener('mouseup', this._UP);
} else {
document.attachhEvent('onmousemove', this._MOVE);
document.attachhEvent('onmouseup', this._UP);
}
}
function move(e) {
e = e || window.event;
let startX = this.startX;
let left = this.left;
let moveX = left + e.pageX - startX;
let curX = moveX < 0 ? 0 : (moveX > maxX ? maxX: moveX);
let percent = curX / maxX * 100;
setCssValue(this, '--percent', percent);
setPercentNum(percent);
}
function up() {
if (document.addEventListener) {
document.removeEventListener('mousemove', this._MOVE);
document.removeEventListener('mouseup', this._UP);
} else {
document.detachEvent('onmousemove', this._MOVE);
document.detachEvent('onmouseup', this._UP);
}
}
slider.addEventListener('mousedown', down);
slider.addEventListener('click', function(e) {
e = e || window.event;
if (e.target === sliderTrack) {
let offsetX = e.offsetX;
let percent = e.offsetX / maxX * 100;
setCssValue(this, '--percent', percent);
setPercentNum(percent);
}
})
//1.添加dom结构
var div=document.createElement('div');
div.setAttribute('class','slider')
var btn1=document.createElement('button');
btn1.setAttribute('class','slider-track');
var btn2=document.createElement('button');
btn2.setAttribute('class','slider-thumb')
var att=document.createAttribute("class");
document.body.appendChild(div);
div.appendChild(btn1);
div.appendChild(btn2);
//2.给.slide设置--percent值为50,此时滑杆在定位中间位置
div.style.setProperty("--percent",50);
//3.点击track轨道按钮,根据点击位置给slide设置--precent
var width=div.offsetWidth;
//另一种方式:width=window.getComputedStyle(div,null).getPropertyValue('width'));
var left=div.offsetLeft;
btn1.addEventListener('click',e=>{
var percent=(e.clientX-left)/width*100;
div.style.setProperty("--percent",percent);
});
//4.拖动thumb滑杆按钮,根据点击位置给slide设置--precent
btn2.addEventListener('mousedown',e=>{
if(e.target==btn2){
var percent=(e.clientX-left)/width*100;
div.style.setProperty("--percent",percent);
document.onmousemove = e=>{
var percent=(e.clientX-left)/width*100;
if(percent<0){
percent=0;
}
if(percent>100){
percent=100;
}
div.style.setProperty("--percent",percent);
}
document.onmouseup=e=>{
document.onmousemove=null;
}
}
})
JS代码
// 问题1:在body标签最后插入DOM结构
var bodyTag = document.getElementsByTagName("body")[0];
var slider=document.createElement("div");
slider.setAttribute("class", "slider");
var track=document.createElement("button");
var thumb=document.createElement("button");
track.setAttribute("class", "slider-track");
thumb.setAttribute("class", "slider-thumb");
slider.appendChild(track);
slider.appendChild(thumb);
bodyTag.appendChild(slider);
// 问题2:设置 --percent的值为50
document.getElementById("question-two").childNodes[1].style.setProperty("--percent", 50);
//问题3:点击trace轨道按钮,根据点击位置给.slider元素设置 --percent
function trackClick(e){
console.log( "trackClick" );
// 点击轨道位置
// offsetLeft 元素 相对于它的直接父元素 的 偏移量
let thumbStart = thumb.offsetParent.offsetLeft;
let thumbWidth = thumb.offsetParent.offsetWidth;
// e.pageX 鼠标点击位置
let newLeft = e.pageX - thumbStart;
let percent = Math.ceil(newLeft/thumbWidth * 100);
slider.style.setProperty("--percent", percent);
console.log( percent );
}
// 监听点击轨道
track.addEventListener('click', e =>trackClick(e), false);
//问题4:拖动thumb滑杆按钮,根据拖动位置给.slider元素设置 --percent
// 是否正在拖动
let isMoving;
// 监听拖动
slider.addEventListener('mousedown', e => {
isMoving = true;
}, false);
// 监听拖动
slider.addEventListener('mousemove', e => {
if(isMoving){
trackClick(e);
}
}, false);
// 监听拖动
slider.addEventListener('mouseup', e => {
isMoving = false;
trackClick(e);
}, false);
我没有做过移动端,我只会pc端(流下弱者的眼泪)
.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;
}
<div class="slider">
<button class="slider-track"></button>
<button class="slider-thumb"></button>
</div>
<div class="slider">
<button class="slider-track"></button>
<button class="slider-thumb"></button>
</div>
<div class="slider">
<button class="slider-track"></button>
<button class="slider-thumb"></button>
</div>
<button id="destory">销毁组件</button>
<button id="reinit">重新绑定组件</button>
<button id="destory1">只销毁第一个组件</button>
//第一题
const slider0 = document.querySelector(".slider"),
style = slider0.style;
style.setProperty("--percent", "50");
//第二题
/***
* 滑动条
* @param doms 要初始化为滑动条的元素或元素类数组
*
* @return {function} destory 销毁组件
*/
function SilderBar(doms) {
if (!(this instanceof SilderBar)) {
return new SilderBar(...arguments);
}
//无论传入的是单dom还是dom类数组,都先转化为数组
if (doms instanceof NodeList) {
doms = [...doms];
} else if (doms instanceof Element) {
doms = [doms];
}
//过滤掉已经被绑定了sliderbar的元素
doms.filter(dom => {
return !this.sliderbarDoms.has(dom);
}).forEach(dom => {
//将元素放到集合中
this.sliderbarDoms.add(dom);
//为每个dom绑定事件
Object.keys(this.sliderbarDomEvents).forEach(key => {
dom.addEventListener(key, this.sliderbarDomEvents[key])
})
})
//若window上面没有绑定过sliderbar对应的事件那么绑定上,否则不再绑定
if (!window.__sliderbar) {
Object.keys(this.sliderbarWindowEvents).forEach(key => {
window.addEventListener(key, this.sliderbarWindowEvents[key])
})
window.__sliderbar = true;
}
return () => {
//解除传入的dom上面绑定的sliderbar事件
doms.forEach(dom => {
Object.keys(this.sliderbarDomEvents).forEach(key => {
dom.removeEventListener(key, this.sliderbarDomEvents[key])
})
this.sliderbarDoms.delete(dom)
})
//当所有的sliderbar都销毁以后,将window上面的事件也删除掉
if (!this.sliderbarDoms.size) {
Object.keys(this.sliderbarWindowEvents).forEach(key => {
window.removeEventListener(key, this.sliderbarWindowEvents[key])
})
delete window.__sliderbar;
}
}
}
Object.assign(SilderBar.prototype, {
sliderbarDoms: new Set(),
sliderbarActiveDoms: new Set(),
sliderbarDomEvents: {
mousedown: function (e) {
SilderBar.prototype.doMove(e, this)
SilderBar.prototype.sliderbarActiveDoms.add(this)
}
},
sliderbarWindowEvents: {
mousemove: (e) => {
SilderBar.prototype.sliderbarActiveDoms.forEach(dom => {
SilderBar.prototype.doMove(e, dom)
})
},
mouseup: () => {
SilderBar.prototype.sliderbarActiveDoms.clear()
}
},
doMove: (e, dom) => {
const position = SilderBar.prototype.getActivePercentagePosition(e, dom);
dom.style.setProperty("--percent", position);
},
//获取激活的百分比位置
getActivePercentagePosition: (e, dom) => {
const mouseX = e.x,
domRect = dom.getBoundingClientRect(),
domX = domRect.x,
domWidth = domRect.width;
if (mouseX < domX) {
return 0;
}
if (mouseX > domX + domWidth) {
return 100;
}
return (mouseX - domX) / domWidth * 100;
}
})
const sliders = document.querySelectorAll('.slider'),
slider = document.querySelector('.slider');
let destory = SilderBar(sliders),
destory1 = SilderBar(slider);
document.querySelector("#destory").addEventListener("click", function () {
destory();
})
document.querySelector("#destory1").addEventListener("click", function () {
destory1();
})
document.querySelector("#reinit").addEventListener("click", function () {
destory = SilderBar(sliders);
})
.slider {
padding: 5px 0;
position: relative;
margin: 30px 10%;
--percent: 50;
}
.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;
}
<div class="slider">
<button class="slider-track"></button>
<button class="slider-thumb"></button>
</div>
;
(function() {
const Utils = {
isMobile: (() => {
return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(
navigator.userAgent
);
})()
};
const slider = document.querySelector(".slider");
const slider_track = slider.querySelector(".slider-track");
const slider_thumb = slider.querySelector(".slider-thumb");
let startMove = false;
slider.addEventListener(Utils.isMobile ? "touchstart" : "mousedown", handleStart, false);
document.addEventListener(Utils.isMobile ? "touchmove" : "mousemove", handleMove, false);
document.addEventListener(Utils.isMobile ? "touchend" : "mouseup", handleEnd, false);
function handleStart(evt) {
if (evt.target === slider_thumb) {
evt.stopPropagation();
startMove = true;
}
}
function handleMove(evt) {
if (startMove) {
render(slider, evt);
}
}
function handleEnd(evt) {
startMove = false;
}
slider.addEventListener(
Utils.isMobile ? "touchend" : "click",
function(evt) {
// 点击轨道
if (evt.target === slider_track) {
render(this, evt);
}
},
false
);
function render(el, evt) {
const xAxis = Utils.isMobile
? evt.changedTouches[0].clientX
: evt.pageX;
const { left, width } = el.getBoundingClientRect();
let percentage = ((xAxis - left) / width) * 100;
percentage = Math.min(Math.max(0, percentage), 100);
el.style.setProperty("--percent", percentage);
}
})();
window.onload = function () {
// question1 start
var sliderDiv = document.createElement("div");
sliderDiv.className = "slider"
sliderDiv.innerHTML = '<button class="slider-track"></button><button class="slider-thumb"></button>'
document.body.append(sliderDiv)
// question1 end
// question2 start
sliderDiv.style.setProperty('--percent', "50")
// question2 end
// question3 start
var sliderTrack = document.querySelector('.slider-track');
var moveTrack2Slide = function (event) {
var offsetWidth = sliderTrack.offsetWidth;
var percent = Math.min(100, Math.ceil(event.offsetX / offsetWidth * 100))
sliderDiv.style.setProperty('--percent', percent + "")
}
sliderTrack.onclick = moveTrack2Slide;
// question3 end
// question4 start
var sliderThumb = document.querySelector('.slider-thumb');
sliderThumb.onmousedown = function (event) {
sliderTrack.addEventListener("mousemove", moveTrack2Slide);
sliderDiv.onmouseleave = function() {
sliderTrack.removeEventListener("mousemove", moveTrack2Slide)
sliderDiv.onmouseleave = null;
}
sliderDiv.onmouseup = function() {
sliderTrack.removeEventListener("mousemove", moveTrack2Slide)
sliderDiv.onmouseup = null;
}
}
//question4 end
}
(function () {
// 1.
var button_slider_track = document.createElement('button')
button_slider_track.classList.add('slider-track')
var button_slider_thumb = document.createElement('button')
button_slider_thumb.classList.add('slider-thumb')
var div_slider = document.createElement('div')
div_slider.classList.add('slider')
div_slider.appendChild(button_slider_track)
div_slider.appendChild(button_slider_thumb)
document.querySelector('body').appendChild(div_slider)
// 2.
var one_state;
document.querySelector('#configToFifty').onclick = function () {
one_state = !one_state
if (one_state) {
div_slider.style.setProperty('--percent', '50')
} else {
div_slider.style.setProperty('--percent', '0')
}
}
// 3.
// 注意 e.layerX 在chrome 和firefox 下的表现比较符合直觉, 在ie下要计算才可以得出正确的值
button_slider_track.onclick = function (e) {
var ratio = (e.offsetX)/this.clientWidth
var result = ratio.toFixed(2)*100
document.querySelector('.slider').style.setProperty('--percent', result)
}
//4.
var button_slider_track_width = parseInt(getComputedStyle(button_slider_track).getPropertyValue('width'), 10)
function mousedown(e) {
var {left} = div_slider.getBoundingClientRect()
document.onmousemove = function (e) {
var button_slider_thumb_disLeft = parseInt(getComputedStyle(button_slider_thumb).getPropertyValue('left'), 10)
var disRatio = (e.pageX - left) / button_slider_track_width
var disPercent = (disRatio.toFixed(2))*100
disPercent = Math.min(disPercent, 100)
disPercent = Math.max(disPercent, 0)
div_slider.style.setProperty('--percent', disPercent)
}
}
document.onmouseup = function () {
document.onmousemove = null
}
button_slider_thumb.onmousedown = mousedown
}())
预览地址 复习一下dom元素大小知识
- client
- getBoundingClientRect()
var body = document.querySelector('body');
body.innerHTML = '<div class="slider"><button class="slider-track"></button><button class="slider-thumb"></button></div>';
var slider = document.querySelector('.slider'),
track = document.querySelector('.slider-track'),
thumb = document.querySelector('.slider-thumb');
slider.style = '--percent: 50';
track.addEventListener('click', function (e) {
var percent = Math.round(e.offsetX / slider.clientWidth * 100);
slider.style = '--percent: ' + percent;
}, false);
thumb.addEventListener('mousedown', function () {
document.addEventListener('mousemove', move);
document.addEventListener('mouseup', function () {
document.removeEventListener('mousemove', move);
});
}, false);
function move(e) {
var left = slider.getBoundingClientRect().left;
var percent = Math.round((e.pageX - left) / slider.clientWidth * 100);
percent = Math.min( Math.max(0,percent),100);
slider.style = '--percent: ' + percent;
}
https://codepen.io/mengxiaoixao/pen/OGRarL?editors=0010
/**** 第一题 ****/
let slider = document.createElement('div')
slider.className = 'slider'
slider.innerHTML = `<button class="slider-track"></button><button class="slider-thumb"></button>`
document.body.appendChild(slider);
/**** 第二题 ****/
let sliderDom = document.getElementsByClassName('slider')[0];
sliderDom.style.setProperty('--percent','50');
/**** 第三题 ****/
let sliderTrack =
document.getElementsByClassName('slider-track')[0],
sliderThumb = document.getElementsByClassName('slider-thumb')[0];
let enableChange = false;
sliderThumb.addEventListener('mousedown',changePosition,false)
document.addEventListener('mousemove',changePosition,false)
document.addEventListener('mouseup',changePosition,false)
function changePosition(evt){
evt.stopPropagation();
evt.type == 'mouseup' && (enableChange = false);
evt.type == 'mousedown'&& (enableChange = true);
if(!enableChange) return;
let {left,width} = sliderDom.getBoundingClientRect();
const percent = Math.min( Math.max(0,(evt.pageX-left)/width*100),100);
sliderDom.style.setProperty('--percent',percent);
}
.slider {
padding: 5px 0;
position: relative;
margin: 30px 10%;
--percent: 0;
}
.slider::before {
content: attr(data-min);
}
.slider::after {
content: attr(data-max);
}
button:focus {
outline: none;
}
.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: 1.5em;
margin: auto -8px;
cursor: move;
}
.slider-thumb:hover::before,
.slider-thumb:focus::before {
display: block;
content: attr(data-value);
transform: translateY(-120%);
}
class Slider {
constructor(options = {}) {
this.value = options.value || 0;
this.min = options.min || 0;
this.max = options.max || 100;
this.percent = options.percent || 0;
let containerId = options.containerId;
containerId = containerId && containerId.indexOf('#') === 0 ? containerId.slice(1) : containerId;
this.container = document.getElementById(containerId) || document.body;
this.render();
this.initWatchers();
this.initOptions();
this.initEvents();
}
get getValue () {
return this.value;
}
render() {
this.sliderElement = this.createSlider();
this.trackElement = this.createTrack();
this.thumbElement = this.createThumb();
this.sliderElement.appendChild(this.trackElement);
this.sliderElement.appendChild(this.thumbElement);
this.container.appendChild(this.sliderElement);
}
initWatchers() {
const self = this;
this.watch('percent', function(percent) {
self.value = Math.ceil((self.max - self.min) * percent / 100 + self.min);
self.thumbElement.setAttribute('data-value', self.value);
})
}
initOptions() {
this.setSliderPercent(this.percent);
this.sliderElement.setAttribute('data-min', this.min);
this.sliderElement.setAttribute('data-max', this.max);
}
watch(prop, cb) {
let value = this[prop];
Object.defineProperty(this, prop, {
get: function() {
return value;
},
set: function(newValue) {
value = newValue;
cb(value);
}
})
}
initEvents() {
const self = this;
let sliderElement = this.sliderElement;
let sliderOffsetLeft = sliderElement.offsetLeft;
let trackElement = this.trackElement;
let moveListener = false;
sliderElement.addEventListener('mousedown', function(e) {
let percent = (e.clientX - sliderElement.offsetLeft) / trackElement.clientWidth * 100;
self.setSliderPercent(percent);
moveListener = true;
})
document.addEventListener('mousemove', function(e) {
if (moveListener) {
let percent = (e.clientX - sliderOffsetLeft) / trackElement.clientWidth * 100;
self.setSliderPercent(percent);
}
})
document.addEventListener('mouseup', function(e) {
moveListener = false;
})
}
setSliderPercent(percent) {
this.percent = Math.min(Math.max(percent, 0), 100);
this.sliderElement.style.setProperty('--percent', this.percent);
}
createSlider() {
let slider = document.createElement('div');
slider.setAttribute('class', 'slider');
return slider;
}
createTrack() {
let track = document.createElement('button');
track.setAttribute('class', 'slider-track');
return track;
}
createThumb() {
let thumb = document.createElement('button');
thumb.setAttribute('class', 'slider-thumb');
return thumb;
}
}
var slider = new Slider();
var slider1 = new Slider({percent: 50});
var slider2 = new Slider({percent: 50, min: -100, max: 200});
// 第一题
const slider = document.createElement('div')
slider.setAttribute('class', 'slider')
const buttonTrack = document.createElement('button')
buttonTrack.setAttribute('class', 'slider-track')
const buttonThumb = document.createElement('button')
buttonThumb.setAttribute('class', 'slider-thumb')
slider.appendChild(buttonTrack)
slider.appendChild(buttonThumb)
document.body.appendChild(slider)
// 第二题
function setPercent(element, value) {
if (value >= 100) {
value = 100
} else if (value <= 0) {
value = 0
}
element.style.setProperty('--percent', value)
}
setPercent(slider, 50)
// 第三题
const buttonTrackWidth = getComputedStyle(buttonTrack).width.slice(0, -2)
buttonTrack.addEventListener('click', e => {
setPercent(slider, Math.round((e.offsetX / buttonTrackWidth) * 100))
})
// 第四题
const sliderOffsetLeft = slider.offsetLeft
let start = false
const startFn = () => (start = true)
const endFn = () => (start = false)
const moveFn = e => {
if (!start) return
const clientX = e.touches ? e.touches[0].clientX : e.clientX
setPercent(
slider,
Math.round(((clientX - sliderOffsetLeft) / buttonTrackWidth) * 100)
)
}
buttonThumb.addEventListener('mousedown', startFn)
buttonThumb.addEventListener('touchstart', startFn)
window.addEventListener('mouseup', endFn)
window.addEventListener('touchend', endFn)
window.addEventListener('mousemove', moveFn)
window.addEventListener('touchmove', moveFn)
let slider = document.createElement('div');
let sliderTrack = document.createElement('button')
let sliderThumb = document.createElement('button')
slider.setAttribute("class", "slider");
sliderTrack.setAttribute("class", "slider-track")
sliderThumb.setAttribute("class", 'slider-thumb');
let bodyCon = document.getElementsByTagName("body")[0]
slider.appendChild(sliderTrack);
slider.appendChild(sliderThumb)
bodyCon.appendChild(slider)
slider.setAttribute("style", '--percent:50')
sliderTrack.onclick = (e) => {
let width = window.getComputedStyle(sliderTrack, 'width').width
let percentWidth = e.offsetX * 100 / parseInt(width)
slider.setAttribute("style", `--percent:${percentWidth}`)
}
sliderThumb.onmousedown = function (e) {
let initX = slider.offsetLeft
let initY = e.clientY
document.onmousemove = function (e) {
let width = window.getComputedStyle(sliderTrack, 'width').width
let distanceX = e.clientX - initX
let distanceY = e.clientY - initY
if (distanceY > 20 || distanceY < -20) {
document.onmousemove = null
} else {
let distancePercent = distanceX * 100 / parseInt(width)
distancePercent = distanceX < 0 ? 0 : distancePercent
distancePercent = distanceX > parseInt(width) ? 100 : distancePercent
slider.setAttribute("style", `--percent:${distancePercent}`)
}
}
}
(function (window) {
var SliderBar = function SliderBar(root, percent) {
if (!root || root.nodeType !== Node.ELEMENT_NODE) {
throw Error('请确保构造函数的第一个参数为DOM节点')
}
this.root = root;
this.percent = percent || 0;
this.isMobile = "ontouchstart" in window;
this.setPercentThroughMouse = this.setPercentThroughMouse.bind(this);
this.getSlidBarPosition = this.getSlidBarPosition.bind(this);
this.render();
this.bindEvent();
this.getSlidBarPosition();
window.addEventListener('resize', this.getSlidBarPosition)
};
SliderProtoType = SliderBar.prototype;
// 将滑动条添加到DOM中。
SliderProtoType.render = function () {
this.sliderBarDom = document.createElement('div');
this.sliderBarDom.setAttribute('class', 'slider');
this.sliderBarDom.setAttribute('style', '--percent:' + this.percent);
this.sliderTrack = document.createElement('button');
this.sliderTrack.setAttribute('class', 'slider-track');
this.sliderThumb = document.createElement('button');
this.sliderThumb.setAttribute('class', 'slider-thumb');
this.sliderBarDom.appendChild(this.sliderTrack);
this.sliderBarDom.appendChild(this.sliderThumb);
this.root.appendChild(this.sliderBarDom);
};
// 将滑动条的位置进行存储
SliderProtoType.getSlidBarPosition = function (percent) {
this.sliderTrackBoundingClientRect = this.sliderTrack.getBoundingClientRect();
};
// 用于设置滑动条的进度
SliderProtoType.setPercent = function (percent) {
this.percent = Math.round(percent * 100) / 100;
if (this.percent < 0) {
this.percent = 0
} else if (this.percent > 100) {
this.percent = 100
}
this.percentChange();
this.sliderBarDom.setAttribute('style', '--percent:' + this.percent);
};
// 用于处理点击和滑动时的操作
SliderProtoType.setPercentThroughMouse = function (e) {
var left = this.sliderTrackBoundingClientRect.left;
var width = this.sliderTrackBoundingClientRect.width;
console.log(e);
var clientX = this.isMobile ? (e.touches && e.touches[0].pageX) : e.clientX
this.setPercent((clientX - left) / width * 100)
};
//绑定事件
SliderProtoType.bindEvent = function () {
var _this = this;
var down = this.isMobile ? "touchstart" : 'mousedown';
var move = this.isMobile ? 'touchmove' : 'mousemove';
var up = this.isMobile ? 'touchend' : 'mouseup';
window.addEventListener(up, function (e) {
window.removeEventListener(move, _this.setPercentThroughMouse)
});
this.sliderThumb.addEventListener(down, function (e) {
window.addEventListener(move, _this.setPercentThroughMouse)
});
this.sliderTrack.addEventListener('click', _this.setPercentThroughMouse)
};
// 执行监听函数,当滑动条变化,会执行实例的onPercentChange方法
SliderProtoType.percentChange = function () {
Object.prototype.toString.call(this.onPercentChange) === "[object Function]" && this.onPercentChange(this.percent)
};
//将构造函数挂在到window
window.SliderBar = SliderBar
})(window);
var firstSlidBar = new SliderBar(document.body);
var secondSlidBar = new SliderBar(document.body);
secondSlidBar.onPercentChange = function (percent) {
document.querySelector('.percent').innerText = percent
};
document.querySelector('.set-percent-btn').addEventListener('click', function () {
firstSlidBar.setPercent(50)
});
- 不要使用pageX,当有水平滚动时候会有bug!
- 点击track定位比较好的方法是使用offsetX,无需计算,其次clientX;
- 避免直接在DOM元素上使用onmouse**方法,因为很容易被重置,建议使用addEventListener。
- 如果你的DOM对象是直接createElement创建,无需在使用选择器进行获取,直接使用即可;
- 误区:过度包装(封装)。过度重用不一定是好事情,会影响代码的可读性。要权衡。大家是成熟的开发人员了,要学会适当冗余。
- 宽度一定要在点击或移动事件中实时获取,不然会有定位问题(如果窗口宽度发生变化)。
- 不要使用offsetLeft,定位是有问题的。
- mousedown移动不应该用在thumb上,也不要非thumb元素都定位(以后元素扩展会有bug)。
- 判断是否支持touchstart事件最好直接'ontouchstart' in document.body。
- body元素直接document.body即可!
- 大家都做了边界判断,很OK,但是,如果超出边界,记得设置为边界值,否则会有bug!