Как мне сделать функцию, чтобы найти координаты элемента независимо от его расположения? - PullRequest
8 голосов
/ 09 марта 2011

Я делаю движок перетаскивания в JavaScript, и я не знаю, как установить правильную позицию dragObj, потому что он изменяется в зависимости от типа позиционирования родительского элемента (Drag также меняется в зависимости от родительского элемента"родительский элемент" и т. д.?)1006 *.В части комментариев прямо перед тем, как я установил атрибуты .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 ]

6 голосов
/ 12 марта 2011

При разработке Javascript jQuery действительно ваш лучший друг, поскольку он упрощает многие из этих (потенциально раздражающих) задач. Я полностью понимаю желание учиться без них; это отличный способ стать опытным.

Взгляните на документы и реализацию jQuery для position и offset, и, надеюсь, это даст вам хорошую идею для начала.

Документы:

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

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

Источник:

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

2 голосов
/ 12 марта 2011

Я не знаю, является ли это именно тем, что вам нужно, но реализация перетаскивания с помощью javascript требует больших усилий и тестирования, особенно когда вы имеете дело с перетаскиванием родительских детей.

Попробуйте это:

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

Может быть, вы можете прочитать его исходный код и использовать его для своих нужд.

1 голос
/ 12 марта 2011

Просто сделайте положение объекта перетаскивания абсолютным -

<code>obj.element = e;
<em>obj.element.style.position = "absolute";</em>
obj.boundElement = null;

Кстати, спасибо за использование jsfiddle, это помогает.

0 голосов
/ 18 марта 2011

Самое простое решение:

Установите элемент на visibility:hidden.Клонируйте элемент, установите клон на position:absolute, выполните перетаскивание.После того, как перетаскивание прекратится (т. Е. Пользователь отпустил левую кнопку мыши), замените клон исходным элементом.

Это позволяет поддерживать элемент в движении в течение операции перетаскивания.Таким образом, если элемент не может быть отброшен в местоположении y (например), вы можете сделать так, чтобы помощник снова привязался к исходному местоположению.

0 голосов
/ 18 марта 2011

На самом деле при работе с поиском положения элементов вы используете его 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 DO упрощает многие из этих утомительных вычислений. Но я действительно думаю, что лучше познакомиться с JS, прежде чем использовать API, поскольку это дает вам понимание того, что такое JS на самом деле.

PS. Не вызывайте этот метод для каждого события mousemove, так как это ухудшит производительность. Intead сохраняет значение элемента (<your node>["startoffset"] = findPos(<your node>)), а затем использует его в скрипте mousemove, чтобы найти его новую позицию. На самом деле, это хорошая практика - сохранять столько значений, сколько вы можете при mousedown, так как mousemove будет называться ALOT, и поэтому должно выполнять как можно меньше вычислений / обходов.

Смотрите это в действии: http://jsfiddle.net/fnwxu/22/

0 голосов
/ 16 марта 2011

Насколько полезен этот фрагмент кода?

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;
}
0 голосов
/ 16 марта 2011

Я новичок в JavaScript.Я нашел ваш вопрос очень интересным и подумал о поиске в Google.Я нашел эти две ссылки, которые могут быть полезны для вас:

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...