Jquery Draggable - 垂直居中光标

发布于 2024-11-02 22:30:39 字数 1852 浏览 1 评论 0原文

我正在开发我的第一个 JQuery 项目,但遇到了一些障碍。我正在尝试允许拖放删除一组嵌套列表 (ul) 的重新排序。除了定位之外,一切都正常。目标是使可拖动对象相对于光标垂直居中(水平移动受到限制),以便可以轻松删除嵌套在其中的元素的 li。这是相关的 JS:

$(function() {
$( ".organizerlink" ).draggable({ axis: "y",
    containment:"#organizer",
    scroll: false ,
    helper: "original",
    revert: "invalid",
    cursorAt: { top: Math.round($(this).outerHeight() / 2)}
});

和 HTML:

<ul id="organizer">
<li class="organizerTarget">&nbsp</li>
<li class="organizerlink" id="dbid-1">Page
    <ul><li class="organizerTarget organizerNewParent">&nbsp;</li></ul>
</li>
<li class="organizerTarget">&nbsp</li>
<li class="organizerlink" id="dbid-2">About
    <ul>
        <li class='organizerTarget'>&nbsp;</li>
        <li class='organizerlink' id="dbid-3">Another Page<ul><li class="organizerTarget organizerNewParent">&nbsp;</li></ul></li>
        <li class='organizerTarget'>&nbsp;</li>
        <li class='organizerlink' id="dbid-4">Example<ul><li class="organizerTarget organizerNewParent">&nbsp;</li></ul></li>
    </ul>
</li>
<li class="organizerTarget">&nbsp</li>
<li class="organizerlink" id="dbid-27">Stuff
    <ul><li class="organizerTarget organizerNewParent">&nbsp;</li></ul>
</li>

我已经尝试过的一些东西:

  • 将cursorAt设置为$(this).height() - 不起作用,我猜测height()会拉入css高度,但它们没有明确定义,因此它会跳到0
  • 将其设置为outerHeight()会在firebug中给我一个错误“elem.style未定义”

我知道jquery中存在outerHeight元素,并且基于API doc 看起来它可以自动计算,即使 CSS 未定义,所以我认为这是正确的方法,也许 $(this) 是只是找错了地方。

I'm working on my first JQuery project, and i've hit a bit of a roadblock. I'm trying to allow drag & drop reordering of a set of nested lists (ul). Everything is working with the exception of the positioning. The goal is to vertically center the draggable relative to the cursor (horizontal movement is restricted), so that an li with elements nested inside it can be easily dropped. Here's the relevant JS:

$(function() {
$( ".organizerlink" ).draggable({ axis: "y",
    containment:"#organizer",
    scroll: false ,
    helper: "original",
    revert: "invalid",
    cursorAt: { top: Math.round($(this).outerHeight() / 2)}
});

and HTML:

<ul id="organizer">
<li class="organizerTarget"> </li>
<li class="organizerlink" id="dbid-1">Page
    <ul><li class="organizerTarget organizerNewParent"> </li></ul>
</li>
<li class="organizerTarget"> </li>
<li class="organizerlink" id="dbid-2">About
    <ul>
        <li class='organizerTarget'> </li>
        <li class='organizerlink' id="dbid-3">Another Page<ul><li class="organizerTarget organizerNewParent"> </li></ul></li>
        <li class='organizerTarget'> </li>
        <li class='organizerlink' id="dbid-4">Example<ul><li class="organizerTarget organizerNewParent"> </li></ul></li>
    </ul>
</li>
<li class="organizerTarget"> </li>
<li class="organizerlink" id="dbid-27">Stuff
    <ul><li class="organizerTarget organizerNewParent"> </li></ul>
</li>

Some stuff I've already tried:

  • setting cursorAt to $(this).height() - didn't work, i'm guessing height() pulls the css heights in, but they aren't defined explicitly so it jumps to 0
  • setting it to outerHeight() gives me an error "elem.style is undefined" in firebug

I know the outerHeight element exists in jquery, and based on the API doc it would appear that it can be calculated automatically, even if the CSS is undefined, so I'm thinking that is the right way to be going, and perhaps $(this) is just the wrong spot to be looking for it.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

白色秋天 2024-11-09 22:30:40

解决了最初的问题,请参阅我最初的帖子的评论。

编辑:

容差选项 “pointer”:鼠标指针与其他项目重叠.

$(".sortable").sortable({
    containment: "parent",
    tolerance: "pointer"
});

Worked around the initial problem, see the comment to my initial post.

EDIT:

Tolerance option "pointer": The mouse pointer overlaps the other item.

$(".sortable").sortable({
    containment: "parent",
    tolerance: "pointer"
});
☆獨立☆ 2024-11-09 22:30:40

如果可拖动对象具有辅助对象,则效果很好。只需将其放入draggable的start方法中即可,如下代码所示。

start: function(event, ui) { 
  $(this).draggable("option", "cursorAt", {
    left: Math.floor(ui.helper.width() / 2),
    top: Math.floor(ui.helper.height() / 2)
  }); 
}

This works fine if draggable have helper object. Just put it in start method of draggable as below code.

start: function(event, ui) { 
  $(this).draggable("option", "cursorAt", {
    left: Math.floor(ui.helper.width() / 2),
    top: Math.floor(ui.helper.height() / 2)
  }); 
}
全部不再 2024-11-09 22:30:40

我只是花了几个小时把头撞在墙上,试图可靠地完成这项工作,所以我想我应该发布解决方案:)

问题:
Draggable 无法在动态值实例化期间为“克隆”拖动设置cursorAt(即可变大小的可拖动代理的中心),因为尚未创建ui.helper!您可以在启动处理程序中设置它,但它不适用于第一次拖动。

解决方案:
将cursorAt设置在start内部,但也手动覆盖连续发生的拖动事件的ui.position。使用firstRun布尔值,您可以防止它不必要地运行。您必须将默认的cursorAt 设置为左​​上角才能重新定位。

享受!

$jobs.each( function( index, element ) {
    var $el = $(element),
        firstRun = true;

    /*
     * jQuery UI Draggable
     * See @link: http://api.jqueryui.com/draggable/
     *
     * Note that for clone drags, the first drag cannot center the proxy because ui.helper hasn't been created yet
     * so need to set it manually for first drag. Subsequent drags can use the cursorAt property.
     * See my @link: 
     */
    $el.draggable({
        cursorAt : [0, 0],          // Set origin then update dynamically
        drag : function( evt, ui ) { // Fires after start event, and continuously during drag
            if ( firstRun ) {
                // Reset proxy position here since cursorAt cannot be set for 
                ui.position.left -= Math.floor( ui.helper.width()/ 2 );
                ui.position.top -= Math.floor( ui.helper.height()/ 2 );
            };
        },
        helper : 'clone',
        start : function( evt, ui ) { // Fires once
            if ( firstRun ) {
                // Center proxy relative to cursor for future drags
                $(this).draggable( 'option', 'cursorAt', {
                    left : Math.floor( ui.helper.width()/ 2 ),
                    top : Math.floor( ui.helper.height()/ 2 )
                });
            };

            // Set cursor ( 'cursor' option just applies style to <body> )
            ui.helper.css( 'cursor', 'move' );
        },
        stop : function( evt, ui ) { // Fires once
            if ( firstRun ) {
                firstRun = false;
            };
        }
    });

I just spent a couple of hours smashing my head against the wall to try to reliably make this work, so I thought I'd post the solution :)

Issue:
Draggable cannot set cursorAt for 'clone' drags during instantiation for dynamic values (i.e. the center of a draggable proxy of variable size) because ui.helper hasn't been created yet! You can set it inside the start handler but it will not work for the first drag.

Solution:
Set the cursorAt inside start, but ALSO manually override the ui.position for the drag event, which occurs continuously. Using a firstRun boolean, you can prevent it from running needlessly. You must set the default cursorAt to the top left for repositioning.

Enjoy!

$jobs.each( function( index, element ) {
    var $el = $(element),
        firstRun = true;

    /*
     * jQuery UI Draggable
     * See @link: http://api.jqueryui.com/draggable/
     *
     * Note that for clone drags, the first drag cannot center the proxy because ui.helper hasn't been created yet
     * so need to set it manually for first drag. Subsequent drags can use the cursorAt property.
     * See my @link: 
     */
    $el.draggable({
        cursorAt : [0, 0],          // Set origin then update dynamically
        drag : function( evt, ui ) { // Fires after start event, and continuously during drag
            if ( firstRun ) {
                // Reset proxy position here since cursorAt cannot be set for 
                ui.position.left -= Math.floor( ui.helper.width()/ 2 );
                ui.position.top -= Math.floor( ui.helper.height()/ 2 );
            };
        },
        helper : 'clone',
        start : function( evt, ui ) { // Fires once
            if ( firstRun ) {
                // Center proxy relative to cursor for future drags
                $(this).draggable( 'option', 'cursorAt', {
                    left : Math.floor( ui.helper.width()/ 2 ),
                    top : Math.floor( ui.helper.height()/ 2 )
                });
            };

            // Set cursor ( 'cursor' option just applies style to <body> )
            ui.helper.css( 'cursor', 'move' );
        },
        stop : function( evt, ui ) { // Fires once
            if ( firstRun ) {
                firstRun = false;
            };
        }
    });
_失温 2024-11-09 22:30:40

如果有多个可拖动对象,Goz 的答案对我不起作用,所以这是我的解决方案,不使用cursorAt选项

var offsetX = null;
var offsetY = null;
$(".item").draggable({
  helper:"clone",
  start:function(e,ui){
    offsetX=null;
    offsetY=null;
  },
  drag:function(e,ui){
    if(offsetX===null){
      offsetX = e.clientX-ui.offset.left;
      offsetY = e.clientY-ui.offset.top;
    }
    ui.position.left += offsetX - Math.floor( ui.helper.outerWidth()/ 2 );
    ui.position.top += offsetY - Math.floor( ui.helper.outerHeight()/ 2 );
            
  }
});
.desk{
  width:300px;
  height:300px;
  border:2px dashed gray;
}

.item {
  padding:8px;
  margin:2px;
  border:1px solid blue;
  background: rgba(0,0,80,.3);
  display:inline-block;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js"></script>
<div class="desk">
  <div class="item">Item 1</div>
  <div class="item" style="width:100px;">Item 2</div>
  <div class="item" style="height:50px;">Item 3</div>
</div>

In case of multiply draggable objects Goz's answer didn't work for me, so here is my solution without using cursorAt option

var offsetX = null;
var offsetY = null;
$(".item").draggable({
  helper:"clone",
  start:function(e,ui){
    offsetX=null;
    offsetY=null;
  },
  drag:function(e,ui){
    if(offsetX===null){
      offsetX = e.clientX-ui.offset.left;
      offsetY = e.clientY-ui.offset.top;
    }
    ui.position.left += offsetX - Math.floor( ui.helper.outerWidth()/ 2 );
    ui.position.top += offsetY - Math.floor( ui.helper.outerHeight()/ 2 );
            
  }
});
.desk{
  width:300px;
  height:300px;
  border:2px dashed gray;
}

.item {
  padding:8px;
  margin:2px;
  border:1px solid blue;
  background: rgba(0,0,80,.3);
  display:inline-block;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js"></script>
<div class="desk">
  <div class="item">Item 1</div>
  <div class="item" style="width:100px;">Item 2</div>
  <div class="item" style="height:50px;">Item 3</div>
</div>

走走停停 2024-11-09 22:30:40

@yuri gor:

你的答案对我有用,但你可以从头开始初始化偏移:

    var offsetX = null;
    var offsetY = null;
    $(".item").draggable({
      helper:"clone",
      start:function(e,ui){
        offsetX = e.clientX-ui.offset.left;
        offsetY = e.clientY-ui.offset.top;
      },
      drag:function(e,ui){
        ui.position.left += offsetX - Math.floor( ui.helper.outerWidth()/ 2 );
        ui.position.top += offsetY - Math.floor( ui.helper.outerHeight()/ 2 );   
     }
    });

@yuri gor:

Your answer worked for me, but you could have just inited the offset from start:

    var offsetX = null;
    var offsetY = null;
    $(".item").draggable({
      helper:"clone",
      start:function(e,ui){
        offsetX = e.clientX-ui.offset.left;
        offsetY = e.clientY-ui.offset.top;
      },
      drag:function(e,ui){
        ui.position.left += offsetX - Math.floor( ui.helper.outerWidth()/ 2 );
        ui.position.top += offsetY - Math.floor( ui.helper.outerHeight()/ 2 );   
     }
    });
月牙弯弯 2024-11-09 22:30:39

我还想在拾取可拖动对象后将它们居中。我的解决方案:

$(".dragme").draggable({ 
    start: function(event, ui) { 
        $(this).draggable("option", "cursorAt", {
            left: Math.floor(this.clientWidth / 2),
            top: Math.floor(this.clientHeight / 2)
        }); 
    }
});

I also wanted to center my draggable objects after I pick them up. My solution:

$(".dragme").draggable({ 
    start: function(event, ui) { 
        $(this).draggable("option", "cursorAt", {
            left: Math.floor(this.clientWidth / 2),
            top: Math.floor(this.clientHeight / 2)
        }); 
    }
});
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文