jqui的draggable功能在scale修改的情况下不能正常运作?

在使用jquery-ui的draggable功能时,若drag对象的父元素经过scale修饰调整了大小的比例,则此时的拖拽会出现拖拽对象瞬移,并且拖拽距离与鼠标距离不同的情况。

阅读 1.4k
1 个回答

我找到了更为正确的做法:修改jquery-ui的源文件,使其能够适配scale修改

首先需要有一个能够获得当前页面的scale值的函数,我想这并不困难,直接来看如何修改这个源文件吧!

在jquery-ui中搜索:_mouseDrag: function( event, noPropagation ) {

如果没有意外的话,您会找到这样一个函数:

_mouseDrag: function( event, noPropagation ) {
  // reset any necessary cached properties (see #5009)
  if ( this.hasFixedAncestor ) {
      this.offset.parent = this._getParentOffset();
  }

  //Compute the helpers position
  this.position = this._generatePosition( event, true );
  this.positionAbs = this._convertPositionTo( "absolute" );

  //Call plugins and callbacks and use the resulting position if something is returned
  if ( !noPropagation ) {
      var ui = this._uiHash();
      if ( this._trigger( "drag", event, ui ) === false ) {
          this._mouseUp( new $.Event( "mouseup", event ) );
          return false;
      }
      this.position = ui.position;
  }

  ※→this.helper[ 0 ].style.left = this.position.left  + "px";
  ※→this.helper[ 0 ].style.top = this.position.top  + "px";

  if ( $.ui.ddmanager ) {
      $.ui.ddmanager.drag( this, event );
  }

  return false;
},

请查看倒数9,8行,我使用了“ ※→ ”作为标注,原文并没有这两个符号,我们需要将其修改为:

this.helper[ 0 ].style.left = this.position.left / return_scale() + "px";
this.helper[ 0 ].style.top = this.position.top / return_scale() + "px";

其中,return_scale()便是您的返回当前scale值的函数,请让left与top值除以这个scale,随后您的draggable便能够在scale下正确移动元素了!

以下为原本的答案,我没有删除它们,因为它们也能够完成同样的功能,如果您有需要的话,可以参看:


这是由于jquery-ui的draggable组件不会正确识别到scale带来的比例性变化,通过代码可以人工调整其出现的位置和移动的举例,以下为代码内容:

//一个作为全局变量的初值,用于存储当前鼠标的位置
var click = { x:0, y:0};
$("可拖拽对象").draggable({
    start: function(event) {
        //将event事件,即当我们开始拖动“可拖拽对象”时进行的点击事件时,鼠标的位置记录下来
        click.x = event.clientX;
        click.y = event.clientY;
    },
    //进入拖动阶段,此时的event是每一个拖动的瞬间,所进行的位移事件,而ui则是“可拖拽对象”
    //(关于ui的详细定义请参考jquery官方文档)
    drag: function(event, ui) {
        //通过任意手段得到父元素的scale的具体的值,此处我将这个值保存进了父元素的“scale”属性中
        var 父元素_scale = $(父元素).attr("scale");
        //这是ui对象在拖动事件开始时的位置,在此处我们将其用作位移的初始量,在scale变化后,这个值不会随之改变,这也是在拖动行为的一瞬间,出现“瞬移”情况的原因
        var original = ui.originalPosition;
        //此时,我们对ui,也就是这个可拖拽对象的位置进行修改,由于通过originalPosition得到的位置是一个Position,即“相对于父元素的位置”,所以此处我们在修改ui的位置时,也要使用position()进行定位,而不是offset()
        ui.position = {
            //此处的值包括:位移起始点,拖动事件的鼠标位置,之前记录拖动开始时的鼠标,详细解释此处难以放置,请见下方详解
            left: (original.left + event.clientX - click.x) / 父元素_scale,
            top:  (event.clientY - click.y + original.top ) / 父元素_scale
        };
    }
})

ui position变化的详解,以下使用ui来代指可拖动对象,请注意区分
1.首先,我们可以得知,original所代表的是拖动开始之前,ui所在的位置,我们将这里设置为位移变化的起始点
2.此处的event.clinetX/Y代表的是drag事件中,鼠标移动后的位置,因此,(event.cliketX - click.x)就表示了从拖拽开始start,到drag的过程中,鼠标在x轴上移动的距离。我们希望ui持续跟随鼠标移动,那么我们就令ui在位置起始点的基础上,在x轴和y轴(也就是left和top)上对应地增加鼠标移动的距离,这样就能使得ui对象的“移动速度”和鼠标的“移动速度”打成一致了
3.最后,我们将得到的这个位置 / 父元素_scale,这包含了两方面的作用,首先,我们要知道的是,在scale后的元素上,鼠标的移动不会收到比例地影响,但是元素的位置变化却会收到scale的等比例影响,例如在scale = 0.5的父元素中向→移动100px,这会在视觉上表现为 想→移动了50px。而" / 父元素_scale"则能够将这种比例地变化调整回来,使得我们的鼠标向→拖拽了100px,对应的ui对象也向→移动了100px,最终便达成了我们需要的,在父元素经过scale处理后的元素上,仍然能够正常地移动

综上所述,这是我在实际的代码编辑中遇到的问题和解决的办法,这可能不是最好的或者效率最高的,但我认为,这仍然可以帮到一些人实现他们的功能。如果我的代码对任何人有帮助或者参考价值,我感到十分荣幸!

另外,在此处附上完整的,不带备注的代码,希望这能便于您使用:

$(您的拖拽元素).draggable({
    start: function(event) {
        click.x = event.clientX;
        click.y = event.clientY;
    },
    drag: function(event, ui) {
        var 您的父元素的scale = return_scale();
        var original = ui.originalPosition;
        ui.position = {
            left: (event.clientX - click.x + original.left) / 您的父元素的scale,
            top:  (event.clientY - click.y + original.top ) / 您的父元素的scale
        };
    }
})
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题