提问人:MasterOfDesaster 提问时间:8/10/2023 更新时间:8/11/2023 访问量:30
Clickevent 在使用下拉列表时显示错误的位置
Clickevent shows wrong position when using dropdown
问:
我想重播 1:1 全点击事件。不幸的是,它不适用于下拉列表。每当我在下拉列表中选择一个值时,它都会显示错误的位置(请随时在我的代码中对其进行测试)。我从 https://stackoverflow.com/a/61732450 那里拿走了事件处理程序,它对我的所有工作都像一个魅力,除了这里。
左图:我所看到的 右:我想要什么
谢谢
let touch_positions = [];
function process_touchevent(e) {
if (
e.type == "touchstart" ||
e.type == "touchmove" ||
e.type == "touchend" ||
e.type == "touchcancel"
) {
var evt = typeof e.originalEvent === "undefined" ? e : e.originalEvent;
var touch = evt.touches[0] || evt.changedTouches[0];
x = touch.pageX;
y = touch.pageY;
} else if (
e.type == "click" ||
e.type == "mousedown" ||
e.type == "mouseup" ||
e.type == "mousemove" ||
e.type == "mouseover" ||
e.type == "mouseout" ||
e.type == "mouseenter" ||
e.type == "mouseleave"
) {
x = e.clientX;
y = e.clientY;
}
touch_positions.push({ x, y, type: e.type, date: new Date() });
var elemDiv = document.createElement("div");
elemDiv.style.cssText =
"position:absolute;width:10px;height:10px;border-radius: 10px;opacity:0.3;z-index:3;background:red;";
let position_text = "left:" + x + "px;top:" + y + "px;";
elemDiv.style.cssText += position_text;
document.body.appendChild(elemDiv);
}
window.addEventListener("touchstart", process_touchevent, false);
window.addEventListener("touchmove", process_touchevent, false);
window.addEventListener("touchcancel", process_touchevent, false);
window.addEventListener("touchend", process_touchevent, false);
window.addEventListener("click", process_touchevent, false);
function draw_all_touch_positions() {
touch_positions.forEach(function (li) {
var elemDiv = document.createElement("div");
elemDiv.style.cssText =
"position:absolute;width:10px;height:10px;border-radius: 10px;opacity:0.3;z-index:3;background:red;";
let position_text = "left:" + li.x + "px;top:" + li.y + "px;";
elemDiv.style.cssText += position_text;
document.body.appendChild(elemDiv);
});
touch_positions = [];
}
<select name="cars" id="cars">
<option value="volvo">Volvo</option>
<option value="saab" selected="">Saab</option>
<option value="mercedes">Mercedes</option>
<option value="audi">Audi</option>
</select>
<button onclick='draw_all_touch_positions()'>Draw</button>
答:
0赞
Chris Barr
8/11/2023
#1
使用 instead of 似乎适用于初始下拉点击,但不适用于 的mousedown
click
<option>
let touch_positions = [];
function process_touchevent(e) {
if (
e.type == "touchstart" ||
e.type == "touchmove" ||
e.type == "touchend" ||
e.type == "touchcancel"
) {
var evt = typeof e.originalEvent === "undefined" ? e : e.originalEvent;
var touch = evt.touches[0] || evt.changedTouches[0];
x = touch.pageX;
y = touch.pageY;
} else if (
e.type == "click" ||
e.type == "mousedown" ||
e.type == "mouseup" ||
e.type == "mousemove" ||
e.type == "mouseover" ||
e.type == "mouseout" ||
e.type == "mouseenter" ||
e.type == "mouseleave"
) {
x = e.clientX;
y = e.clientY;
}
touch_positions.push({ x, y, type: e.type, date: new Date() });
var elemDiv = document.createElement("div");
elemDiv.style.cssText =
"position:absolute;width:10px;height:10px;border-radius: 10px;opacity:0.3;z-index:3;background:red;";
let position_text = "left:" + x + "px;top:" + y + "px;";
elemDiv.style.cssText += position_text;
document.body.appendChild(elemDiv);
}
window.addEventListener("touchstart", process_touchevent, false);
window.addEventListener("touchmove", process_touchevent, false);
window.addEventListener("touchcancel", process_touchevent, false);
window.addEventListener("touchend", process_touchevent, false);
window.addEventListener("mousedown", process_touchevent, false);
function draw_all_touch_positions() {
touch_positions.forEach(function (li) {
var elemDiv = document.createElement("div");
elemDiv.style.cssText =
"position:absolute;width:10px;height:10px;border-radius: 10px;opacity:0.3;z-index:3;background:red;";
let position_text = "left:" + li.x + "px;top:" + li.y + "px;";
elemDiv.style.cssText += position_text;
document.body.appendChild(elemDiv);
});
touch_positions = [];
}
<select name="cars" id="cars">
<option value="volvo">Volvo</option>
<option value="saab" selected="">Saab</option>
<option value="mercedes">Mercedes</option>
<option value="audi">Audi</option>
</select>
<button onclick='draw_all_touch_positions()'>Draw</button>
评论
0赞
MasterOfDesaster
8/11/2023
是的,不幸的是,它不能解决问题:(
0赞
Chris Barr
8/11/2023
没错,但至少更接近一点。这肯定是一个非常奇怪的问题!我和你一样惊讶,我不明白为什么会这样。我想知道您是否可以在整个页面上放置一个透明的 div,该 div 只是为了在发生点击事件时捕获鼠标 x/y 位置?
0赞
MasterOfDesaster
8/11/2023
哇,好主意!但也不起作用:D我假设我必须执行计划 B,即使用 div 自己实现一个下拉列表。:(
0赞
Chris Barr
8/11/2023
#2
我这里有两个潜在的解决方案。
对我来说,一个简单而乖巧的解决方案似乎就是随时跟踪鼠标移动,并将其记录在点击事件中。比以前更简单,甚至更少的代码!
然而,显然非常奇怪,因为它们根本没有记录任何鼠标事件!您会注意到,当菜单打开并且鼠标在它们上移动时,鼠标移动事件会停止注销!唯一的例外是当您指定或更大时。<select>
size="2"
很蹩脚!
const mousePos = {x:0, y:0};
let touch_positions = [];
function process_touchevent(e) {
console.log(e.type, mousePos.x, mousePos.y)
touch_positions.push({ x: mousePos.x, y: mousePos.y, type: e.type, date: new Date() });
draw_touch_position(mousePos.x, mousePos.y);
}
window.addEventListener("touchstart", process_touchevent, false);
window.addEventListener("touchmove", process_touchevent, false);
window.addEventListener("touchcancel", process_touchevent, false);
window.addEventListener("touchend", process_touchevent, false);
window.addEventListener("mousedown", process_touchevent, false);
window.addEventListener("mousemove", (ev)=>{
mousePos.x = ev.clientX;
mousePos.y = ev.clientY;
console.log('move', mousePos.x, mousePos.y)
}, false);
function draw_all_touch_positions() {
touch_positions.forEach(li => {
draw_touch_position(li.x, li.y);
});
touch_positions = [];
}
function draw_touch_position(x, y){
var elemDiv = document.createElement("div");
elemDiv.classList.add("touch-point");
elemDiv.style.cssText = `left:${x}px;top:${y}px;`;
document.body.appendChild(elemDiv);
}
.touch-point {
position:absolute;
width:10px;
height:10px;
border-radius: 10px;
opacity:0.3;
z-index:3;
background:red;
transform: translate(-50%, -50%); /*Make the point appear in the center of the x/y coordinates*/
pointer-events:none; /*don't allow these to become click targets, clicks will pass through now*/
}
<div id="touch-capture"></div>
<select name="cars" id="cars" size="1">
<option value="volvo">Volvo</option>
<option value="saab" selected="">Saab</option>
<option value="mercedes">Mercedes</option>
<option value="audi">Audi</option>
</select>
<select name="cars" id="cars" size="2">
<option value="volvo">Volvo</option>
<option value="saab" selected="">Saab</option>
<option value="mercedes">Mercedes</option>
<option value="audi">Audi</option>
</select>
<input type="text">
<input type="checkbox">
<button type="button" onclick='draw_all_touch_positions()'>Draw</button>
在下一个中,由于似乎无法捕获对 的点击,我们至少可以通过获取选定的期权索引并将其乘以我们预期的期权高度来估计期权位置。选项大小不能通过 CSS 设置样式,并且可能因不同的浏览器和操作系统而异,因此如果您知道这些大小,这可能会起作用。<option>
let touch_positions = [];
function process_touchevent(e) {
if (/^touch(start|move|end|cancel)$/i.test(e.type)) {
var evt = typeof e.originalEvent === "undefined" ? e : e.originalEvent;
var touch = evt.touches[0] || evt.changedTouches[0];
x = touch.pageX;
y = touch.pageY;
} else if (/^click|mouse(down|up|move|over|out|enter|leave)$/i.test(e.type)) {
x = e.clientX;
y = e.clientY;
}
//consolelog(document.elementFromPoint(x,y));
//Cannot get positions for `<option>` elements, so we must estimate!
if(e.target.tagName === "OPTION"){
//console.log(e.target.getBoundingClientRect())
//console.log(getComputedStyles(e.target))
const selectedIndex = e.target.parentElement.selectedIndex;
const optLineHeight = 25; //this might vary in different browsers and OS's!!!!
const parentRect = e.target.parentElement.getBoundingClientRect();
const optMenucenterX = parentRect.x + (parentRect.width / 2);
const optMenuStartY = parentRect.y + parentRect.height;
x = optMenucenterX;
y = optMenuStartY + (optLineHeight * selectedIndex) + 10;
}
touch_positions.push({ x, y, type: e.type, date: new Date() });
draw_touch_position(x, y);
}
window.addEventListener("touchstart", process_touchevent, false);
window.addEventListener("touchmove", process_touchevent, false);
window.addEventListener("touchcancel", process_touchevent, false);
window.addEventListener("touchend", process_touchevent, false);
window.addEventListener("mousedown", process_touchevent, false);
function draw_all_touch_positions() {
touch_positions.forEach(li => {
draw_touch_position(li.x, li.y);
});
touch_positions = [];
}
function draw_touch_position(x, y){
var elemDiv = document.createElement("div");
elemDiv.classList.add("touch-point");
elemDiv.style.cssText = `left:${x}px;top:${y}px;`;
document.body.appendChild(elemDiv);
}
.touch-point {
position:absolute;
width:10px;
height:10px;
border-radius: 10px;
opacity:0.3;
z-index:3;
background:red;
transform: translate(-50%, -50%); /*Make the point appear in the center of the x/y coordinates*/
pointer-events:none; /*don't allow these to become click targets, clicks will pass through now*/
}
<div id="touch-capture"></div>
<select name="cars" id="cars">
<option value="volvo">Volvo</option>
<option value="saab" selected="">Saab</option>
<option value="mercedes">Mercedes</option>
<option value="audi">Audi</option>
</select>
<input type="text">
<input type="checkbox">
<button type="button" onclick='draw_all_touch_positions()'>Draw</button>
这肯定不完美,但它离你的目标更近了。希望这是唯一的例外!
评论
0赞
MasterOfDesaster
8/25/2023
你好克里斯,谢谢你的努力!但对于可用性研究来说,重要的是,要准确地拥有点击的位置,而不是猜测的位置。某些用户可能会在释放鼠标之前按住鼠标键。或者,有些人可能会单击文本外部的区域而不是文本。我想我会做B计划,实现我自己的选择标签:(
评论