Javascript 在HTML/CSS中定位是如何工作的?

Javascript 在HTML/CSS中定位是如何工作的?,javascript,html,css,drag-and-drop,Javascript,Html,Css,Drag And Drop,我正在尝试用JavaScript制作一个拖放引擎。现在,我正在添加一个边界特性,它将把.drag对象困在其父元素中。然而,要做到这一点,我需要了解定位在html中是如何工作的,而我不知道。有人能详细解释一下吗 Javascript引擎: // JavaScript Document var posX; var posY; var element; var currentPos; document.addEventListener("mousedown", drag, false); fun

我正在尝试用JavaScript制作一个拖放引擎。现在,我正在添加一个边界特性,它将把
.drag
对象困在其父元素中。然而,要做到这一点,我需要了解定位在html中是如何工作的,而我不知道。有人能详细解释一下吗

Javascript引擎:

// 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 };
    }
}
一些HTML示例:

<p class="drag bound square">Thing One</p>
<p class="drag square">Thing Two</p>
第一件事

第二件事

请注意,我包含了JavaScript,这样,如果我对如何应用与我所写内容相关的内容有疑问,就可以使用JavaScript。同时,感谢大家的阅读和帮助。StackOverflow是学习如何使用JavaScript编写代码的一个特殊资源

编辑:

1) 我应该说,我编写引擎是为了帮助我学习语言。这是我学习JavaScript的第一周,我希望在使用库之前能够用这种语言编写代码

2) 例如,我真的希望有人解释一下补偿是如何在这里工作的。我想知道如何使用
position:absolute
来制作我的JavaScript引擎,而不是使用
position:relative
,以便元素可以堆叠在彼此的顶部等。

您可能会发现这很有帮助

你到底有什么问题

Absolute从正常的“文档流”中删除元素,并允许您将其定位到所需的位置

相对位置非常类似于静态,但允许您绝对定位其中的元素

Static遵循正常的文档流。(堆叠)

顺便说一下,我建议您使用JQuery或Prototype之类的库或框架,而不是手工构建。它将为您节省数小时的沮丧和在不同浏览器中的测试

编辑: 既然你做这件事很难…我希望我能帮上忙。 我建议您下载Firefox的firebug插件,如果这是您在Chrome工具下使用或熟悉的Javascript控制台

HTML

第一件事

第二件事

这里没有父/子关系。您的意思是将文档作为边界吗? 在BoundMovement调用的元素offSetParent上,freeMovement不调用findPos。 这是未定义的重新调整,因为文档没有该属性

试着用body标签以外的东西来包装这两段文字

<div id='container'>
<p class="drag bound square">Thing One</p>
<p class="drag square">Thing Two</p>
</div>

第一件事

第二件事


您看过这个jQuery演示吗

使用jQuery可以使JavaScript变得更容易,也可以确保代码在跨浏览器中工作。

我认为问题(至少在您的示例中)在于,当您为
boundMovement
中的绑定元素调用
findPos
函数时,您传递的是它的父元素,而它自己没有父元素。因此在
findPos
函数中,这个特定行

if (obj.offsetParent) {
    // ...
返回未定义,因为它没有父项。尝试删除if语句,然后重试。

我已在上发布了一个解决方案

首先,我将要拖动的项嵌套在边界框中:

<div class="bound">Thing One
    <div class="drag square">Thing Two</div>
    <div class="drag square">Thing Three</div>
</div>
<style>
.bound {
    margin: 100px;
    width: 400px;
    height: 400px;
    position: relative;
}
</style>
请注意,这一行:

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';
var x=event.clientX-dragInfo.posX;
如果(x<0)x=0;
如果(x>dragInfo.maxX)x=dragInfo.maxX;
dragInfo.element.style.left=x+'px';

我强烈建议使用jQuery UI进行拖放。这将为您节省很多时间的跨浏览器测试。@马克,我很感谢您的建议,但这是我学习Javascript的第一周。我这样做是为了帮助我学习语言。在开始使用库作为快捷方式之前,我想先学习这门语言。有时你需要重新发明轮子来理解轮子是如何工作的;从零开始写作的pkudos!我对您的代码做了一些修改,并发布在JSFIDLE上。我很快会为我的答案添加更多的解释。我一定会阅读该网页,谢谢。我的确切问题是,我不知道如何使boundMovement()函数在我的javascript中工作。是的,但正如我在最初的帖子和几条评论中所说:在我真正学习javascript之前,我不希望使用jQuery。不过,我很欣赏这个建议=]很抱歉,我没有看到“元素可以堆叠在彼此的顶部”与位置无关。为了改变它们的堆叠顺序,使用cssz-indexStatic“元素可以堆叠在彼此之上”是一个糟糕的选择。我的意思是,静态元素在页面上垂直向下列出,第一个元素出现在第二个元素的上方/之前。不,它的工作方式与它应该的一样。函数
freeMovement()
使用了它,它工作得很好。@Dbz,很有趣。我在
freemotation
中没有看到对
findPos
的调用。在任何情况下,这里有一个JSFIDLE和您的代码以及一些修改:因此,我在您的修改中添加了一些东西,但并不完全有效:@Dbz,首先一件事:绝对定位元素的偏移父元素是第一个父元素(或父元素的父元素,或…),其位置不是静态的。因此,div不是其偏移父对象,因为默认位置是静态的。在这里看到更多:@ZDYN,哦,孩子,这太令人沮丧了。这是否意味着我的
findPos()
函数只能与
position:absolute
元素一起工作;P我确实需要一点解释。有很多更改=/@Dbz您必须将要拖动的项放入边界框中。我已经编辑了我的答案,包括更多的解释。如果您有问题,请再次评论。@Mark,首先,感谢您解释为什么我不需要
findPos()
,这让我发疯了。第二,有必要设置一个
.bound
框是一个好主意吗?这似乎是一个限制,而不是一个特性(尽管它显然有它的优点)。我将查找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';