Как работает позиционирование в HTML / CSS? - PullRequest
2 голосов
/ 26 февраля 2011

Я пытаюсь сделать движок перетаскивания в JavaScript. Прямо сейчас я добавляю функцию bounds, которая будет удерживать объект .drag внутри его родительского элемента. Однако для этого мне нужно понять, как позиционирование работает в html, а я нет. Кто-нибудь может это подробно объяснить?

Javascript Engine:

// JavaScript Document

var posX;
var posY;
var element;
var currentPos;

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

function drag(event) {
    if(~event.target.className.search(/drag/)) {
        element = event.target;
        element.style.zIndex="100";
        currentPos = findPos(element);
        posX = event.clientX -currentPos.x;
        posY = event.clientY -currentPos.y;
            if(~event.target.className.search(/bound/))
                document.addEventListener("mousemove", boundMovement, false);
            else
                document.addEventListener("mousemove", freeMovement, false);
    }
}

function freeMovement(event) { // This functions works

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

    element.style.left = event.clientX - posX + "px";
    element.style.top = event.clientY - posY + "px";
}

function boundMovement(event) { // This function doesn't work

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

    // Below logic is false- I wish to understand why =]
    currentPos = findPos(element.offsetParent);
    if((event.clientX - posX) <= currentPos.x)
        element.style.left = event.clientX - posX + "px";
    if((event.clientY - posY) <= currentPos.y)
        element.style.top = event.clientY - posY + "px";
}

function drop() {
    element.style.zIndex="1";
    document.removeEventListener("mousemove", boundMovement, false);
    document.removeEventListener("mousemove", freeMovement, false);
    document.removeEventListener("mouseup", drop, false);
    //alert("DEBUG_DROP");
}

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

Вот CSS, который я использую:

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

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

.bound {
    /* Class to signify that the drag_object can not leave the parent element */
    ;
}

.square {
    width: 100px;
    height: 100px;
    background: red;
    cursor:move;
}

p {
    padding: 0px;
    margin: 0px;
    outline-style: dotted;
    outline-color: #000;
    outline-width: 1px;
}

Некоторые примеры HTML:

<p class="drag bound square">Thing One</p>
<p class="drag square">Thing Two</p>

Обратите внимание, что я включил JavaScript, чтобы, если у меня возникли вопросы о том, как все применяется по отношению к тому, что я написал. Также спасибо всем за чтение и помощь. StackOverflow был исключительным ресурсом в изучении того, как кодировать в JavaScript.

EDIT:

1) Я должен сказать, что кодирую движок, чтобы помочь мне выучить язык. Это моя первая неделя JavaScript, и я хотел бы иметь возможность писать код на этом языке, прежде чем использовать библиотеку.

2) Например, мне бы очень хотелось, чтобы кто-то объяснил, как здесь работают смещения. Я хотел бы знать, как вместо использования position:absolute для создания своего движка JavaScript я могу использовать position:relative, чтобы элементы могли складываться друг на друге.

Ответы [ 4 ]

2 голосов
/ 26 февраля 2011

Я разместил решение на http://jsfiddle.net/vJ6r6/.

Прежде всего, я вложил элементы, которые нужно перетащить в ограничивающую рамку:

<div class="bound">Thing One
    <div class="drag square">Thing Two</div>
    <div class="drag square">Thing Three</div>
</div>

Также я превратил их вdiv, потому что p не может быть вложенным.(Не забудьте также изменить объявление стиля.)

Затем я устанавливаю стили в ограничивающей рамке:

<style>
.bound {
    margin: 100px;
    width: 400px;
    height: 400px;
    position: relative;
}
</style>

Свойство ключа position: relative, которое вызываетэлементы внутри него должны располагаться относительно него, а не страницы. Обратите внимание, что, поскольку я использую относительное позиционирование, этот пример работает лучше всего, когда вы хотите сохранить элементы в определенном контейнере.

Мои изменения в JavaScript были более радикальными, поэтому вотвсе это:

<script>
var dragInfo;

function down(event) {
    if (~event.target.className.search(/drag/)) {
        document.addEventListener("mouseup", drop, false);
        var t = event.target;
        t.style.zIndex = 100;
        dragInfo = {
            element: t,
            // record the bounds
            maxX: t.parentNode.offsetWidth - t.offsetWidth,
            maxY: t.parentNode.offsetHeight - t.offsetHeight,
            // we don't need findPos, because it's no longer relative to the page
            posX: event.clientX - t.offsetLeft,
            posY: event.clientY - t.offsetTop
        };
        document.addEventListener("mousemove", freeMovement, false);
    }
}

function freeMovement(event) {
    // the min and max calculations keep the X and Y within the bounds
    dragInfo.element.style.left = Math.max(0, Math.min(event.clientX - dragInfo.posX, dragInfo.maxX)) + "px";
    dragInfo.element.style.top = Math.max(0, Math.min(event.clientY - dragInfo.posY, dragInfo.maxY)) + "px";
}

function drop() {
    dragInfo.element.style.zIndex = 1;
    document.removeEventListener("mousemove", freeMovement, false);
    document.removeEventListener("mouseup", drop, false);
}

document.addEventListener("mousedown", down, false);
</script>

Обратите внимание, что эта строка:

dragInfo.element.style.left = Math.max(0, Math.min(event.clientX - dragInfo.posX, dragInfo.maxX)) + 'px';

эквивалентна этому:

var x = event.clientX - dragInfo.posX;
if (x < 0) x = 0;
if (x > dragInfo.maxX) x = dragInfo.maxX;
dragInfo.element.style.left = x + 'px';
1 голос
/ 26 февраля 2011

Я думаю, что проблема (по крайней мере с вашим примером) состоит в том, что когда вы вызываете функцию findPos для ограниченного элемента в boundMovement, вы передаете его родителя, у которого нет своего родителя.Таким образом, внутри функции findPos эта конкретная строка

if (obj.offsetParent) {
    // ...

возвращает значение undefined, поскольку у нее нет родителя.Попробуйте удалить это утверждение if и попробуйте снова.

0 голосов
/ 26 февраля 2011

Вы видели эту демонстрацию jQuery http://jqueryui.com/demos/draggable/#events

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

0 голосов
/ 26 февраля 2011

Вы можете найти это полезным Список css-позиционирования Apart 101

В чем именно состоит ваша проблема?

Абсолют удаляет элемент из обычного «потока документа» и позволяет расположить его там, где вы хотите.

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

Статика соответствует нормальному потоку документов. (Укладки)

Кстати, я рекомендую вам использовать библиотеку или фреймворк, такой как JQuery или Prototype, вместо того, чтобы создавать его вручную. Это сэкономит вам часы разочарования и тестирования в разных браузерах.

Edit: Поскольку вы одержимы этим трудным путем ... Я надеюсь, что смогу помочь. Я рекомендую вам скачать дополнение Firebug для Firefox, если вы им пользуетесь, или знакомиться с Javascript Console в разделе инструментов в Chrome.

HTML

<p class="drag bound square">Thing One</p>
<p class="drag square">Thing Two</p>

Здесь нет родительско-дочерних отношений. Вы подразумевали, что документ является границей? freeMovement не вызывает findPos для элементов offSetParent, где это делает BoundMovement. Это перенастройка не определена, так как документ не имеет этого свойства.

Попробуйте заключить эти два абзаца во что-то, отличное от тега body.

<div id='container'>
<p class="drag bound square">Thing One</p>
<p class="drag square">Thing Two</p>
</div>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...