【发布时间】:2011-10-10 01:12:41
【问题描述】:
我想在相对于被点击元素的坐标中检测MouseEvent 发生的位置。为什么?因为我想在点击的位置添加一个绝对定位的子元素。
我知道在不存在 CSS3 转换时如何检测它(参见下面的描述)。但是,当我添加一个 CSS3 变换时,我的算法会中断,我不知道如何修复它。
我没有使用任何 JavaScript 库,我想了解在纯 JavaScript 中是如何工作的。所以,请不要回答“只使用 jQuery”。
顺便说一句,我想要一个适用于所有鼠标事件的解决方案,而不仅仅是“点击”。这并不重要,因为我相信所有鼠标事件都具有相同的属性,因此相同的解决方案应该适用于所有事件。
背景资料
根据DOM Level 2 specification,MouseEvent 几乎没有与获取事件坐标相关的属性:
-
screenX和screenY返回屏幕坐标(原点是用户显示器的左上角) -
clientX和clientY返回相对于文档视口的坐标。
因此,为了找到MouseEvent相对于点击的元素内容的位置,我必须做这个数学运算:
ev.clientX - this.getBoundingClientRect().left - this.clientLeft + this.scrollLeft
-
ev.clientX是相对于文档视口的坐标 -
this.getBoundingClientRect().left是元素相对于文档视口的位置 -
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 一样。
在这个例子中,唯一的转换是缩放,所以我可以乘以缩放因子来计算正确的坐标。但是,如果我们考虑任意变换(缩放、旋转、倾斜、平移、矩阵),甚至是嵌套变换(另一个变换元素中的变换元素),那么我们确实需要一种更好的方法来计算坐标。
【问题讨论】:
-
'请不要回答“只使用 jQuery”' - 我会单独为你投票...
-
在我看来,如果你有办法获得描述原始变换的 3D 变换矩阵,你就可以通过使它们经历相同的变换来获得坐标,对吧?
getComputedStyle(someElement).getPropertyValue('transform')怎么样?它似乎恰好返回了这样一个矩阵。现在我并不是说矩阵计算很容易,但它们准确且快速...... -
@StijndeWitt 在浏览器中出现了一种官方方式,请参阅我的回答。
标签: javascript html css transform