如何使自定义范围输入适用于触摸屏?
How can I make a custom range input work for touch screens?
我有一个自定义范围滑块。
但是,我 运行 遇到的问题是,我无法使自定义“拇指”(在本例中为 )的滑动在触摸设备上起作用。
这是实时项目:https://wagon-city-guides.herokuapp.com/spots/32
如果您在手机上查看它(我使用的是 iPhone),您仍然会看到原始拇指的边框(我现在故意留下的),它可以滑动并有效,但是火焰(自定义拇指)没有出现......虽然它适用于点击设备。
我只是在寻找 Vanilla JS 解决方案。
这是我的代码:
class RatingSlider {
constructor() {
this.ratingSliderForm = document.querySelector(".js-rating-slider-form");
this.ratingSliderInput = document.querySelector(".js-rating-slider-input");
this.ratingSliderThumb = document.querySelector(".js-rating-slider-thumb");
this.ratingSliderValue = document.querySelector(".js-rating-slider-value");
this.ratingSliderIcon = document.querySelector(".js-rating-slider-icon");
this.isPressed = false;
this.moveEvent;
this.holdEvent;
this.releaseEvent;
this.bind();
}
handleSliding(event) {
if (!this.isPressed) {
return;
}
if (
event.offsetX > 0 &&
event.offsetX < this.ratingSliderInput.offsetWidth
) {
this.ratingSliderThumb.style.left = `${event.offsetX - 10}px`;
this.ratingSliderIcon.style.transform = `scale(${1 +
this.ratingSliderInput.value / 150})`;
this.ratingSliderValue.innerText = `${this.ratingSliderInput.value}°`;
}
}
setRating() {
this.ratingSliderThumb.style.left = `${(this.ratingSliderInput.offsetWidth /
100) *
this.ratingSliderInput.value -
10}px`;
this.ratingSliderIcon.style.transform = `scale(${1 +
this.ratingSliderInput.value / 150})`;
this.ratingSliderValue.innerText = `${this.ratingSliderInput.value}°`;
this.ratingSliderInput.addEventListener(
`${this.holdEvent}`,
() => (this.isPressed = true)
);
this.ratingSliderInput.addEventListener(`${this.releaseEvent}`, () => {
this.isPressed = false;
this.ratingSliderForm.submit();
});
}
setEvents() {
if ("ontouchstart" in document.documentElement) {
this.moveEvent = "touchmove";
this.holdEvent = "touchstart";
this.releaseEvent = "touchend";
} else {
this.moveEvent = "mousemove";
this.holdEvent = "mousedown";
this.releaseEvent = "mouseup";
}
}
bind() {
if (!this.ratingSliderForm) {
return;
}
this.setEvents();
this.setRating();
this.ratingSliderInput.addEventListener(`${this.moveEvent}`, event =>
this.handleSliding(event)
);
}
}
export default RatingSlider;
问题是触摸事件没有 offsetX
和 offsetY
属性。它们的值正在移动设备中返回 undefined
。因此,您需要将这些添加到事件中。
在 handleSliding(event)
方法的开头,添加:
if ("ontouchstart" in document.documentElement) {
event = addOffsetsOnTouch(event);
}
function addOffsetsOnTouch(e) {
let touch = e.touches[0] || event.changedTouches[0];
let target = document.elementFromPoint(touch.clientX, touch.clientY);
event.offsetX = touch.clientX - target.getBoundingClientRect().x;
event.offsetY = touch.clientY - target.getBoundingClientRect().y
return e;
}
根据 Azametzin 的回答,我将处理触摸和非触摸设备偏移的方法重构为以下内容:
handleOffsetOnChange(event) {
if ("ontouchstart" in document.documentElement) {
let touch = event.touches[0];
let target = this.ratingSliderInput;
event.offsetX = touch.clientX - target.getBoundingClientRect().x;
}
if (
event.offsetX > 0 &&
event.offsetX < this.ratingSliderInput.offsetWidth
) {
this.ratingSliderThumb.style.left = `${event.offsetX - 10}px`;
}
}
这是整个文件:
class RatingSlider {
constructor() {
this.ratingSliderForm = document.querySelector(".js-rating-slider-form");
this.ratingSliderInput = document.querySelector(".js-rating-slider-input");
this.ratingSliderThumb = document.querySelector(".js-rating-slider-thumb");
this.ratingSliderValue = document.querySelector(".js-rating-slider-value");
this.ratingSliderIcon = document.querySelector(".js-rating-slider-icon");
this.isPressed = false;
this.setEvents();
this.setPositionThumb();
this.setThumbStyle();
this.bind();
}
setEvents() {
this.moveEvent;
this.startEvent;
this.endEvent;
if ("ontouchstart" in document.documentElement) {
this.moveEvent = "touchmove";
this.startEvent = "touchstart";
this.endEvent = "touchend";
} else {
this.moveEvent = "mousemove";
this.startEvent = "mousedown";
this.endEvent = "mouseup";
}
}
setThumbStyle() {
this.ratingSliderIcon.style.transform = `scale(${1 +
this.ratingSliderInput.value / 150})`;
this.ratingSliderValue.innerText = `${this.ratingSliderInput.value}°`;
}
setPositionThumb() {
this.ratingSliderThumb.style.left = `${(this.ratingSliderInput.offsetWidth /
100) *
this.ratingSliderInput.value -
10}px`;
}
handleOffsetOnChange(event) {
if ("ontouchstart" in document.documentElement) {
let touch = event.touches[0];
let target = this.ratingSliderInput;
event.offsetX = touch.clientX - target.getBoundingClientRect().x;
}
if (
event.offsetX > 0 &&
event.offsetX < this.ratingSliderInput.offsetWidth
) {
this.ratingSliderThumb.style.left = `${event.offsetX - 10}px`;
}
}
bind() {
if (!this.ratingSliderForm) {
return;
}
window.addEventListener("resize", () => this.setPositionThumb());
this.ratingSliderInput.addEventListener(
this.startEvent,
() => (this.isPressed = true)
);
this.ratingSliderInput.addEventListener(this.endEvent, () => {
this.isPressed = false;
this.ratingSliderForm.submit();
});
this.ratingSliderInput.addEventListener(this.moveEvent, (event) => {
if (!this.isPressed) {
return;
}
this.handleOffsetOnChange(event);
this.setThumbStyle();
});
}
}
export default RatingSlider;
我有一个自定义范围滑块。
但是,我 运行 遇到的问题是,我无法使自定义“拇指”(在本例中为 )的滑动在触摸设备上起作用。
这是实时项目:https://wagon-city-guides.herokuapp.com/spots/32
如果您在手机上查看它(我使用的是 iPhone),您仍然会看到原始拇指的边框(我现在故意留下的),它可以滑动并有效,但是火焰(自定义拇指)没有出现......虽然它适用于点击设备。
我只是在寻找 Vanilla JS 解决方案。
这是我的代码:
class RatingSlider {
constructor() {
this.ratingSliderForm = document.querySelector(".js-rating-slider-form");
this.ratingSliderInput = document.querySelector(".js-rating-slider-input");
this.ratingSliderThumb = document.querySelector(".js-rating-slider-thumb");
this.ratingSliderValue = document.querySelector(".js-rating-slider-value");
this.ratingSliderIcon = document.querySelector(".js-rating-slider-icon");
this.isPressed = false;
this.moveEvent;
this.holdEvent;
this.releaseEvent;
this.bind();
}
handleSliding(event) {
if (!this.isPressed) {
return;
}
if (
event.offsetX > 0 &&
event.offsetX < this.ratingSliderInput.offsetWidth
) {
this.ratingSliderThumb.style.left = `${event.offsetX - 10}px`;
this.ratingSliderIcon.style.transform = `scale(${1 +
this.ratingSliderInput.value / 150})`;
this.ratingSliderValue.innerText = `${this.ratingSliderInput.value}°`;
}
}
setRating() {
this.ratingSliderThumb.style.left = `${(this.ratingSliderInput.offsetWidth /
100) *
this.ratingSliderInput.value -
10}px`;
this.ratingSliderIcon.style.transform = `scale(${1 +
this.ratingSliderInput.value / 150})`;
this.ratingSliderValue.innerText = `${this.ratingSliderInput.value}°`;
this.ratingSliderInput.addEventListener(
`${this.holdEvent}`,
() => (this.isPressed = true)
);
this.ratingSliderInput.addEventListener(`${this.releaseEvent}`, () => {
this.isPressed = false;
this.ratingSliderForm.submit();
});
}
setEvents() {
if ("ontouchstart" in document.documentElement) {
this.moveEvent = "touchmove";
this.holdEvent = "touchstart";
this.releaseEvent = "touchend";
} else {
this.moveEvent = "mousemove";
this.holdEvent = "mousedown";
this.releaseEvent = "mouseup";
}
}
bind() {
if (!this.ratingSliderForm) {
return;
}
this.setEvents();
this.setRating();
this.ratingSliderInput.addEventListener(`${this.moveEvent}`, event =>
this.handleSliding(event)
);
}
}
export default RatingSlider;
问题是触摸事件没有 offsetX
和 offsetY
属性。它们的值正在移动设备中返回 undefined
。因此,您需要将这些添加到事件中。
在 handleSliding(event)
方法的开头,添加:
if ("ontouchstart" in document.documentElement) {
event = addOffsetsOnTouch(event);
}
function addOffsetsOnTouch(e) {
let touch = e.touches[0] || event.changedTouches[0];
let target = document.elementFromPoint(touch.clientX, touch.clientY);
event.offsetX = touch.clientX - target.getBoundingClientRect().x;
event.offsetY = touch.clientY - target.getBoundingClientRect().y
return e;
}
根据 Azametzin 的回答,我将处理触摸和非触摸设备偏移的方法重构为以下内容:
handleOffsetOnChange(event) {
if ("ontouchstart" in document.documentElement) {
let touch = event.touches[0];
let target = this.ratingSliderInput;
event.offsetX = touch.clientX - target.getBoundingClientRect().x;
}
if (
event.offsetX > 0 &&
event.offsetX < this.ratingSliderInput.offsetWidth
) {
this.ratingSliderThumb.style.left = `${event.offsetX - 10}px`;
}
}
这是整个文件:
class RatingSlider {
constructor() {
this.ratingSliderForm = document.querySelector(".js-rating-slider-form");
this.ratingSliderInput = document.querySelector(".js-rating-slider-input");
this.ratingSliderThumb = document.querySelector(".js-rating-slider-thumb");
this.ratingSliderValue = document.querySelector(".js-rating-slider-value");
this.ratingSliderIcon = document.querySelector(".js-rating-slider-icon");
this.isPressed = false;
this.setEvents();
this.setPositionThumb();
this.setThumbStyle();
this.bind();
}
setEvents() {
this.moveEvent;
this.startEvent;
this.endEvent;
if ("ontouchstart" in document.documentElement) {
this.moveEvent = "touchmove";
this.startEvent = "touchstart";
this.endEvent = "touchend";
} else {
this.moveEvent = "mousemove";
this.startEvent = "mousedown";
this.endEvent = "mouseup";
}
}
setThumbStyle() {
this.ratingSliderIcon.style.transform = `scale(${1 +
this.ratingSliderInput.value / 150})`;
this.ratingSliderValue.innerText = `${this.ratingSliderInput.value}°`;
}
setPositionThumb() {
this.ratingSliderThumb.style.left = `${(this.ratingSliderInput.offsetWidth /
100) *
this.ratingSliderInput.value -
10}px`;
}
handleOffsetOnChange(event) {
if ("ontouchstart" in document.documentElement) {
let touch = event.touches[0];
let target = this.ratingSliderInput;
event.offsetX = touch.clientX - target.getBoundingClientRect().x;
}
if (
event.offsetX > 0 &&
event.offsetX < this.ratingSliderInput.offsetWidth
) {
this.ratingSliderThumb.style.left = `${event.offsetX - 10}px`;
}
}
bind() {
if (!this.ratingSliderForm) {
return;
}
window.addEventListener("resize", () => this.setPositionThumb());
this.ratingSliderInput.addEventListener(
this.startEvent,
() => (this.isPressed = true)
);
this.ratingSliderInput.addEventListener(this.endEvent, () => {
this.isPressed = false;
this.ratingSliderForm.submit();
});
this.ratingSliderInput.addEventListener(this.moveEvent, (event) => {
if (!this.isPressed) {
return;
}
this.handleOffsetOnChange(event);
this.setThumbStyle();
});
}
}
export default RatingSlider;