【问题标题】:How do I make a function to find the coordinates of an element regardless of its positioning?无论元素的位置如何,如何创建一个函数来查找元素的坐标?
【发布时间】:2011-03-09 03:46:29
【问题描述】:

我正在用 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 也可以进行任何类型的定位?

重要请不要推荐使用库(除非您建议查看它以获取有关它们如何处理定位的提示)。原因是我只是在学习语言并且构建东西对我有帮助这样做。在我理解语言之前学习图书馆有什么意义?

最重要的是,我非常感谢您的所有帮助。谢谢。

【问题讨论】:

    标签: javascript html css drag-and-drop


    【解决方案1】:

    在开发 Javascript 时,jQuery 确实是您最好的朋友,因为它简化了许多这些(可能很烦人)的任务。不过,我完全渴望在没有他们的情况下学习;这是精通的好方法。

    查看 jQuery 的文档和 positionoffset 的实现,希望这会给你一个很好的起点。

    文档:

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

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

    来源:

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

    【讨论】:

    【解决方案2】:

    我不知道这是否正是你所需要的,但使用 javascript 实现拖放需要大量的努力和测试,尤其是在处理父子拖动时。

    试试这个:

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

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

    【讨论】:

    • 不幸的是,我认为这不符合我的需要;但是,它有很多小想法,我可以在我的中实现,太好了! (+1)
    【解决方案3】:

    只需将拖动对象的位置设为绝对 -

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

    顺便说一句,感谢您使用 jsfiddle,它有帮助。

    【讨论】:

    • 感谢您的建议,但我正在努力使元素 不需要 必须是绝对的 =]
    • 你必须!元素不需要是绝对的,它可以是任何东西,但是当您开始拖动时,您将其设为绝对以获得适当的拖动效果。你试过用相对位置拖动元素吗?
    • 所以你是说var temp = object.element.style.position; object.element.style.position = "absolute"; drag(); object.element.style.position = temp; ?
    • 你应该简单地添加 dragObj.element.style.position = "absolute";在设置新值之前(在 dragObj.element.style.left =...; 之前)到你的函数 freeMovement。不要把它改回旧的 style.position,因为你的新位置会丢失。我用你的小提琴来测试,它有效
    • @Pablo,它不应该工作。至少不是我想要的方式。如果它是绝对的,那么它可以超越其他元素。我希望用户可以选择是否可以“降落”在其他元素上的天气。
    【解决方案4】:

    这段代码有多大用处?

    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;
    }
    

    【讨论】:

    • 不幸的是,它没有帮助(我已经有了我自己的代码版本),因为它不适用于嵌套在不同定位类型容器中的所有定位类型 dragObjs元素 =/
    【解决方案5】:

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

    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 确实简化了许多这些繁琐的计算。但我真的认为最好在使用 API 之前了解 JS,因为它可以让您了解 JS 的真正含义。

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

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

    【讨论】:

      【解决方案6】:

      最简单的解决方案:

      将元素设置为visibility:hidden。克隆元素,设置克隆为position:absolute,进行拖动。一旦拖动停止(即用户松开鼠标左键),将克隆替换为原始元素。

      这允许您在可拖动操作期间保持元素流动。这样,如果无法将元素放置在位置 y(例如),您可以让助手快速返回到原始位置。

      【讨论】:

        【解决方案7】:

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

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2012-01-09
          • 2013-08-06
          • 2020-03-19
          • 2019-03-12
          • 2021-05-06
          • 1970-01-01
          • 2017-08-20
          相关资源
          最近更新 更多