我想检测哪里 MouseEvent
发生了,在相对于被点击元素的坐标。为什么?因为我想在点击的位置添加一个绝对定位的子元素。
我知道当不存在 CSS3 转换时如何检测它(见下面的描述)。但是,当我添加 CSS3 转换时,我的算法出现故障,我不知道如何修复它。
我没有使用任何 JavaScript 库,我想了解纯 JavaScript 的工作原理。所以,请不要回答“只使用 jQuery”。
顺便说一句,我想要一个适用于所有 MouseEvent 的解决方案,而不仅仅是“单击”。这并不重要,因为我相信所有鼠标事件都共享相同的属性,因此相同的解决方案应该适用于所有鼠标事件。
背景资料
根据 DOM Level 2 specification , 一个 MouseEvent
具有与获取事件坐标相关的几个属性:
screenX
和screenY
返回屏幕坐标(原点是用户显示器的左上角)clientX
和clientY
返回相对于文档视口(viewport)的坐标。
因此,为了找到 MouseEvent
相对于被单击元素内容的位置,我必须进行以下计算:
ev.clientX - this.getBoundingClientRect().left - this.clientLeft + this.scrollLeft
ev.clientX
是相对于文档视口(viewport)的坐标this.getBoundingClientRect().left
是元素相对于文档视口(viewport)的位置this.clientLeft
是元素边界和内部坐标之间的边框(和滚动条)数量this.scrollLeft
是元素内部的滚动量
getBoundingClientRect()
, clientLeft
和 scrollLeft
在 CSSOM View Module 指定.
没有 CSS 转换的实验(它有效)
令人困惑? Try the following piece of JavaScript and HTML .单击后,一个红点应该正好出现在单击发生的位置。这个版本“非常简单”并且按预期工作。
function click_handler(ev) {
var rect = this.getBoundingClientRect();
var left = ev.clientX - rect.left - this.clientLeft + this.scrollLeft;
var top = ev.clientY - rect.top - this.clientTop + this.scrollTop;
var dot = document.createElement('div');
dot.setAttribute('style', 'position:absolute; width: 2px; height: 2px; top: '+top+'px; left: '+left+'px; background: red;');
this.appendChild(dot);
}
document.getElementById("experiment").addEventListener('click', click_handler, false);
<div id="experiment" style="border: 5px inset #AAA; background: #CCC; height: 400px; position: relative; overflow: auto;">
<div style="width: 900px; height: 2px;"></div>
<div style="height: 900px; width: 2px;"></div>
</div>
尝试添加 CSS 转换(失败)
现在,try adding a CSS transform
:
#experiment {
transform: scale(0.5);
-moz-transform: scale(0.5);
-o-transform: scale(0.5);
-webkit-transform: scale(0.5);
/* Note that this is a very simple transformation. */
/* Remember to also think about more complex ones, as described below. */
}
该算法不知道转换,因此计算出错误的位置。此外,Firefox 3.6 和 Chrome 12 的结果不同。Opera 11.50 的行为与 Chrome 一样。
在这个例子中,唯一的变换是缩放,所以我可以乘以缩放因子来计算正确的坐标。但是,如果我们考虑任意变换(缩放、旋转、倾斜、平移、矩阵),甚至嵌套变换(一个变换元素在另一个变换元素中),那么我们确实需要一种更好的方法来计算坐标。
最佳答案
您遇到的行为是正确的,并且您的算法没有中断。首先,CSS3 Transforms 的设计不会干扰盒子模型。
试图解释...
当您在元素上应用 CSS3 转换时。元素采用一种相对定位。因为周围的元素不受转换元素的影响。
例如想象水平行中的三个 div。如果应用缩放变换来减小中心 div 的大小。周围的 div 不会向内移动以占据曾经占据转换元素的空间。
示例:http://jsfiddle.net/AshMokhberi/bWwkC/
所以在盒子模型中,元素实际上并没有改变大小。只有它的渲染尺寸发生变化。
您还必须记住,您正在应用缩放变换,因此您的元素“实际”大小实际上与其原始大小相同。您只是在改变它的感知大小。
解释..
假设您创建了一个宽度为 1000 像素的 div 并将其缩小到原来的 1/2。 div 的内部大小仍然是 1000px,而不是 500px。
所以你的点的位置相对于 div 的“真实”大小是正确的。
我修改了你的例子来说明。
说明
- 单击 div 并将鼠标保持在同一位置。
- 找到错误位置的点。
- 按 Q,div 将变成正确的大小。
- 将鼠标移动到您点击的正确位置上的点。
http://jsfiddle.net/AshMokhberi/EwQLX/
因此,为了使鼠标点击坐标与 div 上的可见位置相匹配,您需要了解鼠标基于窗口返回坐标,并且您的 div 偏移量也基于其“真正的"尺寸。
由于您的对象大小是相对于窗口的,因此唯一的解决方案是使用与您的 div 相同的比例值来缩放偏移坐标。
然而,根据您设置 div 的 Transform-origin 属性的位置,这可能会变得棘手。因为这会影响偏移量。
看这里。
http://jsfiddle.net/AshMokhberi/KmDxj/
希望这对您有所帮助。
关于javascript - 如何获取具有 CSS3 转换的元素的 MouseEvent 坐标?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6773481/