vvcomponent
Version:
VV组件
158 lines (137 loc) • 5.68 kB
JavaScript
class aSlider extends HTMLElement {
constructor() {
super();
this.attachShadow({ mode: 'open' });
this.min = parseFloat(this.getAttribute('min')) || 0;
this.max = parseFloat(this.getAttribute('max')) || 100;
this.value = parseFloat(this.getAttribute('value')) || 0;
this.step = parseFloat(this.getAttribute('step')) || 1;
this.render();
}
static get observedAttributes() {
return ['min', 'max', 'value', 'step'];
}
attributeChangedCallback(name, oldValue, newValue) {
if (oldValue !== newValue) {
this[name] = parseFloat(newValue);
if (name === 'value') {
this.value = Math.max(this.min, Math.min(this.value, this.max));
}
this.updateThumbPosition(this.sliderThumb, this.sliderTrack, this.value);
}
}
render() {
const sliderContainer = document.createElement('div');
sliderContainer.classList.add('slider-container');
const sliderTrack = document.createElement('div');
sliderTrack.classList.add('slider-track');
const sliderThumb = document.createElement('div');
sliderThumb.classList.add('slider-thumb');
sliderContainer.appendChild(sliderTrack);
sliderTrack.appendChild(sliderThumb);
this.shadowRoot.appendChild(sliderContainer);
const style = document.createElement('style');
style.textContent = this.getStyles();
this.shadowRoot.appendChild(style);
this.sliderTrack = sliderTrack;
this.sliderThumb = sliderThumb;
this.updateThumbPosition(sliderThumb, sliderTrack, this.value);
this.addDragEvents(sliderTrack, sliderThumb);
}
getStyles() {
return `
.slider-container {
width: 100%;
padding: 10px;
position: relative;
}
.slider-track {
width: 100%;
height: 8px;
background: #d3d3d3; /* Light gray background */
border-radius: 5px;
position: relative;
}
.slider-thumb {
width: 20px;
height: 20px;
background: #ffffff; /* White slider thumb */
border: 2px solid #007bff; /* Blue border */
border-radius: 50%;
position: absolute;
top: 50%;
transform: translate(-50%, -50%);
cursor: pointer;
}
.slider-track::before {
content: '';
position: absolute;
height: 100%;
background: #007bff; /* Blue for the left side */
border-radius: 5px;
width: var(--value, 0%);
}
`;
}
addDragEvents(track, thumb) {
let isDragging = false;
const getEventClientX = (event) => {
return event.touches ? event.touches[0].clientX : event.clientX;
};
const updateThumbPosition = (event) => {
const rect = track.getBoundingClientRect();
let offsetX = getEventClientX(event) - rect.left;
offsetX = Math.max(0, Math.min(offsetX, rect.width));
const percentage = (offsetX / rect.width) * 100;
const rawValue = this.min + (percentage / 100) * (this.max - this.min);
const steppedValue = Math.round(rawValue / this.step) * this.step;
this.value = Math.max(this.min, Math.min(steppedValue, this.max));
thumb.style.left = `${((this.value - this.min) / (this.max - this.min)) * 100}%`;
track.style.setProperty('--value', `${((this.value - this.min) / (this.max - this.min)) * 100}%`);
};
const dispatchStartEvent = () => {
const startEvent = new CustomEvent('start', {
detail: { value: this.value },
});
this.dispatchEvent(startEvent);
};
const dispatchChangeEvent = () => {
const changeEvent = new CustomEvent('change', {
detail: { value: this.value },
});
this.dispatchEvent(changeEvent);
};
const startDrag = (event) => {
isDragging = true;
dispatchStartEvent();
};
const moveDrag = (event) => {
if (isDragging) {
updateThumbPosition(event);
}
};
const endDrag = () => {
if (isDragging) {
isDragging = false;
dispatchChangeEvent();
}
};
thumb.addEventListener('mousedown', startDrag);
thumb.addEventListener('touchstart', startDrag, { passive: true });
document.addEventListener('mousemove', moveDrag);
document.addEventListener('touchmove', moveDrag, { passive: true });
document.addEventListener('mouseup', endDrag);
document.addEventListener('touchend', endDrag);
track.addEventListener('click', (event) => {
updateThumbPosition(event);
dispatchChangeEvent();
});
}
updateThumbPosition(thumb, track, value) {
const percentage = ((value - this.min) / (this.max - this.min)) * 100;
thumb.style.left = `${percentage}%`;
track.style.setProperty('--value', `${percentage}%`);
}
}
globalThis.Slider = aSlider;
customElements.define('iftc-slider', aSlider);