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

Posted

技术标签:

【中文标题】如何在 javascript 中为我的可拖动对象设置“边界”区域?【英文标题】:How can I set a "bounding" area for my drag-able object in javascript? 【发布时间】:2011-07-05 02:05:39 【问题描述】:

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

现在我的 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 ***
    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 */


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

而且我的 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>

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

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

    如果其中一个父元素 IS 绑定,那么我没有正确设置绑定坐标(同样,我不知道如何)

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

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;

设置边界框的正确数学是什么?为什么?我可以摆脱.bound 类中的position: relative 吗?我可以让.drag 类不是position: absolute 吗?我知道所有这些事情可能会极大地影响边界函数的编写方式。如果我不得不.drag 类或 .bound 类不需要特定类型的 position 之间进行选择,我会选择将 .bound 类设置为任何类型定位。

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

编辑:

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

【问题讨论】:

+1 - 绝对值得自己学习 JavaScript 而不是依赖库。但是,您可能可以从解构 jQuery UI 可拖动库的源代码中学到很多东西(我知道它专门支持将任何元素设置为边界框)。如果你能读懂 JS,jQuery UI 中的大部分代码都很清楚,所以它可能会对你有所帮助:jqueryui.com/demos/draggable/#constrain-movement @Tim 谢谢。我实际上正在考虑阅读不同的库是如何做到的,但是当我查看其他人的代码时,我不知道发生了什么。我还没有足够的 JavaScript 知识。但是,我最后一次查看某人的“拖放”版本是在我编写自己的代码之前,所以链接很有可能会派上用场。如果只有代码被大量评论!此外,这些库可以帮助我了解如何构建代码。我想实现引擎,使其易于使用。 【参考方案1】:

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

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

首先,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;

强制执行边界是对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";

我可以摆脱 .bound 类中的位置:relative 吗?是的。

我可以让 .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;

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

【讨论】:

非常感谢!我将仔细阅读所有内容以确保我理解它。 所以,我有一堆问题!默认情况下,边界框似乎设置为父元素。在我进行检查以找到正确的父元素用作边界框之前。我还能这样做吗? -即使有任何类型的位置设置(以及如何设置)?另外,如何将.drag.bound 类设置为任何类型的定位?数学是怎样的? 当然你仍然可以这样做!您可能想检查object.style.position,然后执行您的计算。当它是relative 时,minBoundX 和 minBoundY 将为 0(正如我上面所说的)。 所以@Kit,我如何从这里jsfiddle.net/yJVtH 到在数学中允许不同类型的定位?您能否将 cmets 添加到我刚刚发布的 jsfiddle 中,向我展示我需要针对不同类型的定位进行调整的位置? 这是一个更新的:jsfiddle.net/yJVtH/3。我做了一些改变,所以看看。我也认为你的数学不会像我想象的那样改变。您唯一需要弄清楚的是一个更好的findPos 函数,它可以解释边界元素的相对/绝对定位。为此,我绝对会推荐查看 jQuery 或 prototype.js 是如何做到的,因为有很多怪癖……尤其是跨浏览器。【参考方案2】:

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

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

【讨论】:

感谢推荐书。我会看看获得它。至于链接给出的算法,我有一个非常相似的函数(引擎中的最后一个)已经称为 findPos()。现在是上午 12 点,所以我明天将深入阅读整个网页。谢谢! =]

以上是关于如何在 javascript 中为我的可拖动对象设置“边界”区域?的主要内容,如果未能解决你的问题,请参考以下文章

在 JavaScript 中为我的牌组生成卡片时出现随机错误

我如何在 javascript 中为我的游戏制作图像跟随另一个图像

如何在我的 GraphQL 中为对象中的对象列表定义类型

保存并加载动态创建的可拖动元素的位置(jQuery-UI)

jQuery - 窗口滚动后的可拖动位置问题

如何在 Java 中创建可拖动对象?