应用变换后如何定位和拖动元素

6

我有一段JavaScript代码,可以完美地拖动对象......但是当我将页面缩小到0.5倍时...

transform:scale(0.5);

鼠标位置和拖动的对象位置不同,我该如何修复?或者这可能吗?...谢谢。

这是一个 jsfiddle 示例:http://jsfiddle.net/Xcb8d/65/


也许可以看一下这个网址:https://dev59.com/zOo6XIcBkEYKwwoYQiO7 - conceptdeluxe
1
可以的。您需要检查比例值,然后将其应用于您的逻辑。这是一个fiddle(硬编码值-0.5),可以更新您的鼠标移动(_move_elem)逻辑:http://jsfiddle.net/Xcb8d/77/ (初始鼠标按下未作更改) - Jack
谢谢@JackPattishallJr。你的答案最接近了。 :-) - user3204806
2个回答

5
这很有趣,让我重新考虑只使用offsetHeight和offsetWidth的所有位置,而不知道如果应用了元素变换,这些JavaScript中的只读属性将返回不正确的值。
"诀窍"在于clientHeight/offsetHeight不会正确报告它们的变换属性。为了从元素中获取正确的尺寸信息,您需要调用 getBoundingClientRect()。然后,您可以计算缩放元素的正确像素信息,从而允许您执行正确的定位。
检索边界矩形允许您从视口获取像素信息,然后您可以将此信息与浏览器中的clientHeight进行比较,以确定缩放的偏移高度和位置。
我修改了一些事件绑定,仅供测试。此外,我添加了另一个类来生成一个四分之一大小的对象,以证明它可以在任何缩放比例下工作。
CSS:
html,
body {
  width:100%;
  height:100%;
}

.half-size
{
   transform:scale(0.5);
  -moz-transform:scale(0.5);
  -webkit-transform:scale(0.5);
}
.quarter-size
{
   transform:scale(0.25);
  -moz-transform:scale(0.25);
  -webkit-transform:scale(0.25);
}

#draggable-element {
  width:100px;
  height:100px;
  background-color:#666;
  color:white;
  padding:10px 12px;
  cursor:move;
  position:relative; /* important (all position that's not `static`) */
  display:block;
}

JavaScript:

var selected = null, // Object of the element to be moved
    x_pos = 0, y_pos = 0, // Stores x & y coordinates of the mouse pointer
    x_elem = 0, y_elem = 0; // Stores top, left values (edge) of the element

var elem_height = 0;
var elem_width = 0;

// Will be called when user starts dragging an element
function _drag_init(elem) {
    // Store the object of the element which needs to be moved
    selected = elem;

    var boundingRectangle = selected.getBoundingClientRect();

    y_elem = (selected.offsetHeight - (boundingRectangle.bottom - boundingRectangle.top)) / 2;
    x_elem = (selected.offsetWidth - (boundingRectangle.right - boundingRectangle.left)) / 2

    half_elem_height = (boundingRectangle.bottom - boundingRectangle.top) / 2;
    half_elem_width = (boundingRectangle.right - boundingRectangle.left) /2;

    document.addEventListener('mousemove', _move_elem, false);
    document.addEventListener('mouseup', _destroy, false);    
};

// Will be called when user dragging an element
function _move_elem(e) 
{
  x_pos = e.clientX;
  y_pos = e.clientY;

  selected.style.left = ((x_pos - x_elem) - half_elem_width) + 'px';
  selected.style.top = ((y_pos - y_elem) - half_elem_height) + 'px';    
}
// Destroy the object when we are done and remove event binds
function _destroy() {
  selected = null;
  document.removeEventListener('mousemove', _move_elem);
  document.removeEventListener('mouseup', _destroy);
}

// Bind the functions...
document.getElementById('draggable-element').onmousedown = function () {
    _drag_init(this);
};

HTML:

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>JS Bin</title>
</head>
<body> 
<div id="draggable-element" class='half-size'>Drag me!</div>    
</body>
</html>

点击下方查看实时预览

http://jsbin.com/moyadici/1/edit (我更喜欢 jsBin 而非 jsFiddle,因为它可以实时更新)

我修改了一些事件绑定,仅用于我的初始测试。此外,我将转换分解成样式,以便尝试其他转换方式。在呈现“四分之一大小”时,测试结果正确。这证明它可以正常工作,而不需要魔数来进行位置计算。


需要注意的是,getBoundingClientRect 会在每次鼠标按下时触发一次布局/回流。 - Jack
@JackPattishallJr。所以调用getBoundingClientRect会导致回流吗? - cgatian
是的 - 至少在 WebKit 中!(我的大部分工作都是为移动 Safari 而做的,所以我更熟悉那里 - 我不确定 Moz/IE 如何处理 getBoundingClientRect...) - Jack
有一些方法可以解决这个问题,比如将其存储起来,这样就不必重新查询了。 - cgatian

1
不是真正的答案,但太长了不能作为评论,因为它仍然跳动,可能第一次尝试失败...
在Firefox中,使用pointer-events,您可以尝试限制将捕捉鼠标的区域。
创建一个位于中心的内部元素,该元素的大小为其自身缩放后的大小。
您的fiddle说要scale(0.5)一个100px的正方形,因此让我们用伪元素在中间画一个50px的正方形。
将元素的pointer-events设置为none,并将其重置为伪元素的正常状态。现在我们有一个50px的正方形,它将接受鼠标。一旦元素缩小到50px,我们仍然有这个区域起反应。(正方形只是看起来更小了,但保持了相同的空间。)
为了完成您的fiddle测试,让我们添加到body:transform-origin:top left;,现在我们应该能够拖动这个正方形。
Firefox测试:http://jsfiddle.net/Xcb8d/78/

Chrome测试: http://jsfiddle.net/Xcb8d/79/ (添加负边距)

点击几次后,它真的会跳出限制 :)


希望它能给一些提示。

阅读此文:http://css-tricks.com/get-value-of-css-rotation-through-javascript/

我认为,我们可以从body中获取transform的值,并在函数内更新计算,这样我们就可以修改比例值而不用触及脚本。

新手测试:http://jsfiddle.net/Xcb8d/82/

例如:从原始fiddle更新的函数

// Will be called when user dragging an element
function _move_elem(e) {
var el = window.document.body;
var st = window.getComputedStyle(el, null);
var tr = st.getPropertyValue("transform") ;

var values = tr.split('(')[1];
    values = values.split(')')[0];
    values = values.split(',');

var a = values[0];
var b = values[1];
var c = values[2];
var d = values[3];
    x_pos = document.all ? window.event.clientX : e.pageX;
    y_pos = document.all ? window.event.clientY : e.pageY;
    if (selected !== null) {
        selected.style.left = ((x_pos / a) - x_elem) + 'px';
        selected.style.top = ((y_pos /  d) - y_elem) + 'px';
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接