如何创建一个函数来查找元素的坐标,而不管它的位置如何?

时间:2011-03-09 03:46:29

标签: javascript html css drag-and-drop

我在JavaScript中制作拖放引擎,我不知道如何设置dragObj的正确位置,因为它会根据父元素的定位类型而改变(dragObj是否也会根据其父元素的变化而改变) “父元素”等。?)。

所以,我的dragObj看起来像这样:

function makeObj(event) {
    var obj = new Object();
    var e = event.target;

    obj.element = e;
    obj.boundElement = null;

    while(e = e.parentNode) {
        if(~e.className.search(/bound/)) { //if(/bound/.test(e.className)) {
            obj.boundElement = e;
            break;
        }
    }

    if(obj.boundElement == null)
        obj.boundElement = document.body;


    // I would like to find the correct minimum bounds with findPos(); however, I need
    // findPos() to work with every type of positioning (absolute, relatice, ect.)

    //var elemPos = findPos(obj.boundElement);
    //obj.minBoundX = elemPos.x;
    //obj.minBoundY = elemPos.y;

    obj.minBoundX = obj.boundElement.offsetLeft + obj.boundElement.offsetWidth - obj.element.offsetWidth;
    obj.minBoundY = obj.boundElement.offsetTop + obj.boundElement.offsetHeight - obj.element.offsetHeight;

    obj.maxBoundX = obj.boundElement.offsetLeft;
    obj.maxBoundY = obj.boundElement.offsetTop;

    setHelperBoxPos(obj);

    obj.posX = event.clientX - obj.element.offsetLeft;
    obj.posY = event.clientY - obj.element.offsetTop;

    return obj;
}

所以,当我做一个dragObj时,我也设置了它的“位置”和它的bounding element。在我设置.minBoundX.minBoundY属性之前的评论部分中,我解释了如何设置它们;但是,它不起作用,因为findPos()函数不起作用。

这是findPos()函数:

function findPos(obj) { // Donated by `lwburk` on StackOverflow
    var curleft = curtop = 0;
    if (obj.offsetParent) {
        do {
            curleft += obj.offsetLeft;
            curtop += obj.offsetTop;
        } while (obj = obj.offsetParent);
        return { x: curleft, y: curtop };
    }
}

我相信如果bounding element设置position: absolute;,此功能有效,但我希望用户能够设置其定位类型。此外,bounding element.bound类设置,dragObj由.drag类设置。

这是HTML:

<div id="min" class="helper-box" style="border: 1px solid blue;"></div>
<div id="max" class="helper-box" style="border: 1px solid red;"></div>

<div id="center">
    <h1>Hello World! <hr /></h1>
    <div id="box" class="bound">
        <p class="drag square"> One </p>
        <p class="drag square"> Two </p>
    </div>
</div>

这是CSS:

@charset "utf-8";
/* CSS Document */


* {
    padding: 0px;
    margin: 0px;
}

body {
    background-color:#DFDFDF;
}

.drag {
    position: absolute;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
}

.bound {
    ;
}

.square {
    width: 100px;
    height: 100px;
    background: #1047A9;
    cursor:move;
    border-radius: 25px;
    -moz-border-radius: 25px;
}

#center {
    width: 500px;
    margin: auto;
    margin-top: 50px;
    background-color: #29477F;
    color: #E8E8E8;
    text-align: center;
    border-radius: 25px;
    -moz-border-radius: 25px;
}

#box {
    background-color: #009EBE;
    height: 275px;
    border-radius: 0 0 25px 25px;
    -moz-border-radius: 0 0 25px 25px;
    opacity: 1.0;
}

.helper-box {
    position: absolute;
    width: 5px;
    height: 5px;
}    

这是整个引擎:

// JavaScript Document

var dragObj;

document.addEventListener("mousedown", down, false);

function down(event) {
    if(~event.target.className.search(/drag/)) {
        dragObj = makeObj(event);
        dragObj.element.style.zIndex="100";
        document.addEventListener("mousemove", freeMovement, false);
    }
}

function freeMovement(event) {

    if (typeof(dragObj.element.mouseup) == "undefined")
        document.addEventListener("mouseup", drop, false);
    //Prevents redundantly adding the same event handler repeatedly

    dragObj.element.style.left = Math.max(dragObj.maxBoundX, Math.min(dragObj.minBoundX, event.clientX - dragObj.posX)) + "px";
    dragObj.element.style.top = Math.max(dragObj.maxBoundY, Math.min(dragObj.minBoundY, event.clientY - dragObj.posY)) + "px";
}

function drop() {
    dragObj.element.style.zIndex="1";

    document.removeEventListener("mousemove", freeMovement, false);
    document.removeEventListener("mouseup", drop, false);
    //alert("DEBUG_DROP");
}


function makeObj(event) {
    var obj = new Object();
    var e = event.target;

    obj.element = e;
    obj.boundElement = null;

    while(e = e.parentNode) {
        if(~e.className.search(/bound/)) { //if(/bound/.test(e.className)) {
            obj.boundElement = e;
            break;
        }
    }

    if(obj.boundElement == null)
        obj.boundElement = document.body;


    // I would like to find the correct minimum bounds with findPos(); however, I need
    // findPos() to work with every type of positioning (absolute, relatice, ect.)

    //var elemPos = findPos(obj.boundElement);
    //obj.minBoundX = elemPos.x;
    //obj.minBoundY = elemPos.y;

    obj.minBoundX = obj.boundElement.offsetLeft + obj.boundElement.offsetWidth - obj.element.offsetWidth;
    obj.minBoundY = obj.boundElement.offsetTop + obj.boundElement.offsetHeight - obj.element.offsetHeight;

    obj.maxBoundX = obj.boundElement.offsetLeft;
    obj.maxBoundY = obj.boundElement.offsetTop;

    setHelperBoxPos(obj);

    obj.posX = event.clientX - obj.element.offsetLeft;
    obj.posY = event.clientY - obj.element.offsetTop;

    return obj;
}

function findPos(obj) { // Donated by `lwburk` on StackOverflow
    var curleft = curtop = 0;
    if (obj.offsetParent) {
        do {
            curleft += obj.offsetLeft;
            curtop += obj.offsetTop;
        } while (obj = obj.offsetParent);
        return { x: curleft, y: curtop };
    }
}

    function setHelperBoxPos(obj) {
        var minBox = document.getElementById('min');
        minBox.style.left = obj.minBoundX + 'px';
        minBox.style.top = obj.minBoundY + 'px';

        var maxBox = document.getElementById('max');
        maxBox.style.left = obj.maxBoundX + 'px';
        maxBox.style.top = obj.maxBoundY + 'px';
    }

为方便起见,我也做了一个jsfiddle:http://jsfiddle.net/2XGhK/

那么,我如何创建一个允许不同类型定位的findPos()函数。我是否需要创建另一个findPos()函数以允许dragObj成为任何类型的定位?

重要请不要建议使用图书馆(除非您建议查看它们如何处理定位的提示)。原因是我只是在学习语言并且构建有助于我的东西做到这一点。在我理解这门语言之前学习图书馆有什么意义?

最重要的是,我非常感谢你的帮助。谢谢。

7 个答案:

答案 0 :(得分:6)

在开发Javascript时,jQuery确实是你最好的朋友,因为它简化了许多这些(可能令人讨厌的)任务。尽管如此,我完全挖掘了没有他们的学习欲望;这是一种变得精通的好方法。

看一下jQuery的positionoffset的文档和实现,希望这会让你对起点有一个好主意。

文档:

http://api.jquery.com/position/

http://api.jquery.com/offset/

来源:

https://github.com/jquery/jquery/blob/master/src/offset.js

答案 1 :(得分:2)

我不知道这是否正是你所需要的,但是使用javascript实现拖放需要付出很多努力和测试,特别是当你处理父子拖动时。

试试这个:

http://interface.eyecon.ro/demos/drag.html

也许您可以阅读其源代码并使用它来满足您的需求。

答案 2 :(得分:1)

简单地将拖动对象的位置设为绝对 -

obj.element = e;
obj.element.style.position = "absolute";
obj.boundElement = null;

不过,谢谢你使用jsfiddle,它有所帮助。

答案 3 :(得分:0)

我是JavaScript的初学者。我发现你的问题非常有趣,并想到谷歌搜索它。我找到了这两个可能对您有用的链接:

http://www.codingforums.com/archive/index.php/t-84055.html
  http://www.codeproject.com/KB/scripting/DragDrop_Part-2.aspx

答案 4 :(得分:0)

此代码片段有用吗?

var position = {};
var dragObj = "";
function initDrag(e){
    e = e || window.event;

    position.objLeft = parseInt(dragObj.style.left);
    position.objTop = parseInt(dragObj.style.top);
    if( isNaN(position.objLeft) )
        position.objLeft = 0;
    if( isNaN(position.objTop) )
        position.objTop = 0;        
    position.startX = e.clientX;
    position.startY = e.clientY;
    if( document.addEventListener )
    {
        e.preventDefault();
        dragObj.addEventListener('mousemove',startDrag,false);
        dragObj.addEventListener('mouseup',stopDrag,false);
        dragObj.addEventListener('mouseout',stopDrag,false);
    }
    else
    {
        dragObj.attachEvent('onmousemove',startDrag);
        dragObj.attachEvent('onmouseup',stopDrag);
        dragObj.attachEvent('onmouseout',stopDrag);
    }
}

function startDrag(e){
    e = e || window.event;

    dragObj.style.left = position.objLeft+e.clientX-position.startX;
    dragObj.style.top = position.objTop+e.clientY-position.startY;
    return false;
}

答案 5 :(得分:0)

实际上,在查找元素位置时,使用其offsetLeft(/Top)。并且每个元素都有offsetParent来自该位置的起源。当你拖动一个元素时,最好根据整个文档(读取)知道它的位置,这样你就可以获得更精确的点。因此,要找到elementes位置,您必须创建以下函数:

function findPos(elm) {
    var testElm = elm, pos = {x:0, y:0};
    while( !!testElm && testElm.tagName.toLowerCase() !== "body" ) {
        pos.x += testElm.offsetLeft;
        pos.y += testElm.offsetTop;
        // important to use offsetParent instead of just parentNode,
        // as offsetParent will be where the element gets its offset from.
        // And that is not necesarily it parentNode!
        testElm = testElm.offsetParent;
    }
    return pos;
}

但我同意其他一些观点,jQuery DO简化了很多繁琐的计算。但我真的认为在使用API​​之前最好先了解JS,因为它可以让你了解JS的真正含义。

PS。不要为每个mousemove事件调用此方法,因为它会影响性能。 Intead将值保存在元素(<your node>["startoffset"] = findPos(<your node>))上,然后在mousemove脚本中使用它来查找其新位置。实际上,最好在mousedown上保存尽可能多的值,因为mousemove将被称为ALOT,因此应尽可能少地进行计算/遍历。

查看实际操作:http://jsfiddle.net/fnwxu/22/

答案 6 :(得分:0)

最简单的解决方案:

将元素设置为visibility:hidden。克隆元素,将克隆设置为position:absolute,执行拖动。拖动停止后(即用户释放了鼠标左键),将克隆替换为原始元素。

这允许您在可拖动操作期间将元素保持在流中。这样,如果元素无法在位置y中删除(例如),则可以让帮助程序快照回原始位置。