jQuery UI draggable拖拽失效:从调色板拖入工作区的元素首次无法移动
侧边调色板拖拽元素到工作区draggable属性失效问题
问题现象
开发支持侧边调色板拖拽元素到工作区的UI功能时,出现draggable属性失效的异常:
- 页面预先存储了一组隐藏div,和调色板每一项一一对应
- 点击调色板项时,会克隆对应隐藏元素、移除id属性后追加到editor容器,为其初始化draggable属性,限定拖拽范围为父容器,同时设置元素位置跟随鼠标、触发对应鼠标事件,实现无需二次点击即可直接拖动的效果
- 鼠标松开时会销毁临时克隆元素的draggable属性并移除该元素;如果元素被拖放到workspace工作区,则将元素追加到工作区容器,为所有工作区内的
.editor-pane元素初始化resizable和draggable属性,限定其仅可在工作区内移动 - 异常表现:刚拖入的元素完全无法拖动,只有拖入新元素后,之前的元素才能正常拖拽
相关代码
CSS
#editor{ position: relative; height: 100%; width: 100%; background: lightcyan; } #elements{ display: none; } #palette{ height: 100%; width: 125px; float: left; background: lightgrey; } .editor-pane{ height: 10%; width: 20%; float: left; background: lightyellow; position: absolute; } .editor-palette-item{ width: 16px; height: 16px; } .palette-item-container{ cursor: pointer; cursor: hand; padding: 16px; } #workspace{ height: 100%; width: 70%; float: left; background: white; } body{ width: 97%; height: 750px; }
HTML
<div id="editor" style="border: solid; "> <div id="palette"> <div class="palette-item-container" elementId="element1"> <div class="ui-icon ui-icon-alert"></div> Element1 </div> <div class="palette-item-container" elementId="element2"> <div class="ui-icon ui-icon-alert"></div> Element2 </div> <div class="palette-item-container" elementId="element3"> <div class="ui-icon ui-icon-alert"></div> Element3 </div> </div> <div id="workspace"> </div> <div id="elements"> <div id="element1" class="editor-pane"></div> <div id="element2" class="editor-pane"></div> <div id="element3" class="editor-pane"></div> </div> </div>
原始JavaScript代码
var ElementCopy = null; $('#palette .palette-item-container').mousedown(function(evt) { ElementCopy = $('#' + $(this).attr("elementId")).clone().removeAttr('id'); $('#editor').append(ElementCopy); ElementCopy.draggable({ containment: "parent" }); ElementCopy.css("left", evt.clientX - 20 + "px"); ElementCopy.css("top", evt.clientY - 20 + "px"); ElementCopy.trigger(evt); ElementCopy.mouseup(function(e){ ElementCopy.draggable( "destroy" ); ElementCopy.remove(); }); }); $('#workspace').droppable({ drop: function(evt) { if (ElementCopy){ $('#workspace').append(ElementCopy); $('#workspace .editor-pane').resizable({ containment: "parent" }) .draggable({ containment: "parent" }); } } });
问题根因
- 事件触发顺序冲突:
drop事件的触发晚于临时元素绑定的mouseup事件,元素刚被追加到工作区,之前绑定的mouseup就销毁了draggable属性,甚至触发了元素移除逻辑,导致新元素拖拽失效 - 重复绑定逻辑问题:每次drop都给所有工作区的
.editor-pane重新初始化draggable,旧元素会被重新绑定事件,所以只有拖入新元素的时候,上一次拖入的元素才能正常拖拽 - 容器切换后坐标丢失:元素从editor容器移到workspace容器时,absolute定位的参考父容器发生变化,没有转换坐标也会影响拖拽行为
修复后代码
var ElementCopy = null; // 标记元素是否已经被放入工作区 var isDropped = false; $('#palette .palette-item-container').mousedown(function(evt) { isDropped = false; ElementCopy = $('#' + $(this).attr("elementId")).clone().removeAttr('id'); $('#editor').append(ElementCopy); ElementCopy.draggable({ containment: "parent" }); ElementCopy.css("left", evt.clientX - 20 + "px"); ElementCopy.css("top", evt.clientY - 20 + "px"); ElementCopy.trigger(evt); ElementCopy.mouseup(function(e){ // 只有没放入工作区的临时元素才执行销毁移除逻辑 if(!isDropped && ElementCopy) { ElementCopy.draggable("destroy"); ElementCopy.remove(); ElementCopy = null; } }); }); $('#workspace').droppable({ drop: function(evt, ui) { if (ElementCopy){ isDropped = true; // 解绑临时元素的mouseup事件 ElementCopy.off('mouseup'); // 销毁之前的draggable实例 ElementCopy.draggable("destroy"); // 转换坐标,适配workspace的定位参考系 const workspaceOffset = $('#workspace').offset(); ElementCopy.css({ left: ui.offset.left - workspaceOffset.left + 'px', top: ui.offset.top - workspaceOffset.top + 'px' }); // 追加到工作区 $('#workspace').append(ElementCopy); // 只给当前新拖入的元素初始化resizable和draggable,避免重复绑定 ElementCopy.resizable({ containment: "parent" }).draggable({ containment: "parent" }); ElementCopy = null; } } });
内容的提问来源于stack exchange,提问作者Ao ShiroYami
相关产品推荐
相关产品推荐

