javascript 如何在javascript中为我的可拖动对象设置“边界”区域?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/5130810/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-25 16:04:12  来源:igfitidea点击:

How can I set a "bounding" area for my drag-able object in javascript?

javascripthtmlcssdrag-and-drop

提问by Dbz

I'm making a Drag and Drop JavaScript engine. I learned how to set a bounding box as the parent element. However, now I wish to set the bounding box to any parent of any parent, or as the entire page (bound-less).

我正在制作一个拖放 JavaScript 引擎。我学会了如何将边界框设置为父元素。但是,现在我希望将边界框设置为任何父级的任何父级,或作为整个页面(无边界)。

Right now my Javascript Engine looks like:

现在我的 Javascript 引擎看起来像:

// JavaScript Document

var dragObj;

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

function down(event) {
    if(~event.target.className.search(/drag/)) {
        dragObj = makeObj(event.target);
        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(0, Math.min(event.clientX - dragObj.posX, dragObj.boundX)) + "px";
    dragObj.element.style.top = Math.max(0, Math.min(event.clientY - dragObj.posY, dragObj.boundY)) + "px";
}

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

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

function makeBoundlessObj(e) {
    var obj = new Object();
    obj.element = e;

    obj.boundX = e.parentNode.offsetWidth - e.offsetWidth;
    obj.boundY = e.parentNode.offsetHeight - e.offsetHeight;

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

    return obj;
}

function makeObj(e) {
    obj = new Object();
    obj.element = e;

    obj.boundX = e.parentNode.offsetWidth - e.offsetWidth;
    obj.boundY = e.parentNode.offsetHeight - e.offsetHeight;

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

    var curleft = curtop = 0;
    if (e.offsetParent) {
        do {
            curleft += e.offsetLeft;
            curtop += e.offsetTop;
            //alert(e.id + ":" + e.innerHTML);
            if(~e.className.search(/bound/)) {
                obj.boundX = curleft - obj.element.offsetLeft;
                obj.boundY = curtop - obj.element.offsetTop;
                return obj;
            }

        } while (e = e.offsetParent);
    }

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

My CSS is as follows:

我的 CSS 如下:

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


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

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

.bound {
    position: relative;
}

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

#center {
    width: 500px;
    height: 300px;
    margin: auto;
    margin-top: 50px;
    background-color:#ccc;
    text-align: center;
    border-radius: 25px;
    -moz-border-radius: 25px;
}

#box {
    background-color: #FF3;
    height: 278px;
    border-radius: 0 0 25px 25px;
    -moz-border-radius: 0 0 25px 25px;
    opacity: 0.5;
}

And my HTML is pretty clean:

我的 HTML 非常干净:

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

I've attempted to make the proper functions multiple times. I'll give one that I've made which doesn't work, and I'll list why:

我曾多次尝试使正确的功能。我会给一个我做的但不起作用的,我会列出原因:

  1. If it doesn't have bounds, I set the default bounds as the parent element (because I don't know how to set bounds as the entire page)

  2. If one of the parent elements ISa bound, then I am not setting the bound coordinates correctly (again, I don't know how)

  1. 如果它没有边界,我将默认边界设置为父元素(因为我不知道如何将边界设置为整个页面)

  2. 如果父元素之一边界,那么我没有正确设置边界坐标(同样,我不知道如何)

Oh, and I set the bounds while I create the drag_object.

哦,我在创建drag_object 时设置了边界。

JavaScript creation function:

JavaScript 创建函数:

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

    obj.boundX = e.parentNode.offsetWidth - e.offsetWidth;
    obj.boundY = e.parentNode.offsetHeight - e.offsetHeight;

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

    var curleft = curtop = 0;
    if (e.offsetParent) {
        do {
            curleft += e.offsetLeft;
            curtop += e.offsetTop;
            //alert(e.id + ":" + e.innerHTML);
            if(~e.className.search(/bound/)) {
                obj.boundX = curleft - obj.element.offsetLeft;
                obj.boundY = curtop - obj.element.offsetTop;
                return obj;
            }

        } while (e = e.offsetParent);
    }

    return obj;
}

What is the correct math for setting the bounding box and why? Can I get rid of the position: relativein the .boundclass? Can I make .dragclass not position: absolute? I know all of these things will probably greatly affect how the bounding function is written. If I hadto choose between having the .dragclass or the .boundclass not need a certain type of position, I would choose that the .boundclass be set to any kind of positioning.

设置边界框的正确数学是什么,为什么?我可以position: relative.bound课堂上摆脱吗?我可以.drag不上课position: absolute吗?我知道所有这些事情可能会极大地影响边界函数的编写方式。如果我必须在拥有.drag类或.bound不需要某种类型的类之间position做出选择,我会选择将.bound类设置为任何类型的定位。

Thank you all for reading and helping! It means a lot to me; I'm a full time (boarding) high school student with very little free time =/

感谢大家的阅读和帮助!它对我意义重大; 我是一名全日制(寄宿)高中生,空闲时间很少=/

EDIT:

编辑:

I should note that I'm on my tenth day of learning Javascript- or fifteenth-hour depending on how you look at it, and I would like to learn the language before I start using libraries like jQuery. This engine is an academic exercise I've made for myself for the sake of knowledge and learning the language =]

我应该注意,我正在学习 Javascript 的第十天或第十五个小时,这取决于你如何看待它,我想在开始使用像 jQuery 这样的库之前学习这门语言。这个引擎是我为了知识和学习语言而为自己做的学术练习=]

回答by Kit Menke

The first thing I noticed is that you didn't have a minimum boundary. You'll need that in order to enforce the upper AND lower bound.

我注意到的第一件事是你没有最低限度。您需要它来强制执行上限和下限。

What is the correct math for setting the bounding box and why?

设置边界框的正确数学是什么,为什么?

First thing is that dragObjneeds to account for both boundaries (applies to position: absolute):

首先dragObj需要考虑两个边界(适用于position: absolute):

// parentNode is our bounding box
// the minimum boundary is based on the top left corner of our container
obj.minBoundX = e.parentNode.offsetLeft;
obj.minBoundY = e.parentNode.offsetTop;

// the maximum is the bottom right corner of the container
// or.. the top left (x,y) + the height and width (h,y) - the size of the square
obj.maxBoundX = obj.minBoundX + e.parentNode.offsetWidth - e.offsetWidth;
obj.maxBoundY = obj.minBoundY + e.parentNode.offsetHeight - e.offsetHeight;

Enforcing the boundaries is a simple update to freeMovement:

强制执行边界是对以下内容的简单更新freeMovement

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

Can I get rid of the position: relative in the .bound class?Yup.

我可以摆脱 .bound 类中的 position: relative 吗?对。

Can I make .drag class not position: absolute?Yup. You'll just want to change your positions to be relative and your calculations to account for this. For example, your minimum bound will now be 0.

我可以让 .drag 类不是 position: absolute 吗?对。您只需要将您的头寸更改为相对位置,并通过您的计算来说明这一点。例如,您的最小界限现在将为 0。

// parentNode is our bounding box
// the minimum boundary is based on the top left corner of our container
obj.minBoundX = 0;
obj.minBoundY = 0;

Here is the JSFiddle for the position:absoluteversion: http://jsfiddle.net/feWcQ/(works with Firefox 4). I also added two tiny boxes that show your boundaries. Hopefully my answer helps you!

这是该position:absolute版本的 JSFiddle :http: //jsfiddle.net/feWcQ/(适用于 Firefox 4)。我还添加了两个小盒子来显示你的界限。希望我的回答能帮到你!

回答by Paul

So, before I take a stab, I'd strongly recommend the book by OReilly, "Definitive Guide to JavaScript". I learned a ton in there (and subsequently forgot it when I didnt have to use it every day).

所以,在我尝试之前,我强烈推荐 OReilly 的书“JavaScript 权威指南”。我在那里学到了很多东西(后来当我不必每天使用它时忘记了它)。

So there's a lot of ways to skin this cat, but I the hardest part is to get the positions of the relevant things in a cross-browser way without using a library. I don't actually recall the exact syntax (so I won't try) but basically what you'll need to do is find the bounding box's position and the dragged element's position using this formula: http://blog.firetree.net/2005/07/04/javascript-find-position/and then account for element widths and so on to stay inside the boxes.

所以有很多方法可以给这只猫剥皮,但我最难的部分是在不使用库的情况下以跨浏览器的方式获取相关事物的位置。我实际上不记得确切的语法(所以我不会尝试)但基本上你需要做的是使用这个公式找到边界框的位置和拖动元素的位置:http: //blog.firetree.net /2005/07/04/javascript-find-position/然后考虑元素宽度等以留在框内。