使用Robot Framework实现Canvas画布拖拽放置失效问题求助
Robot Framework Canvas拖拽无法触发drop问题
问题描述
使用Robot Framework在Canvas画布上实现拖拽操作时出现异常:脚本可以拖动目标对象,但始终无法触发放置(drop)动作。已尝试修改JavaScript脚本、按偏移量执行拖拽、模拟「鼠标按下-途经中间位置移动-鼠标抬起」拖拽流程等多种方案,均未解决问题。
现有问题代码片段截图:
现有自定义拖拽JS实现如下:
var dataTransfer={ dropEffect:'', effectAllowed:'all', files:[], items:{}, types:[], setData:function(format,data) { this.items[format]=data; this.types.append(format); }, getData:function(format) { return this.items[format]; }, clearData:function(format){} }; var emit=function(event,target) { var evt=document.createEvent('Event'); evt.initEvent(event,true,false); evt.dataTransfer=dataTransfer; target.dispatchEvent(evt); }; function getElementByXpath(path) { return document.evaluate(path, document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue; } var DragNDrop=function(src,tgt) { src = getElementByXpath(src); tgt = getElementByXpath(tgt); emit('dragstart',src); emit('dragenter',tgt); emit('dragover',tgt); emit('drop',tgt); emit('dragend',src); return true; }
问题根因
- 现有代码模拟的是HTML5原生
drag系列事件,绝大多数Canvas场景的拖拽实现都不监听原生拖放事件,而是直接监听底层的mousedown/mousemove/mouseup鼠标事件,事件类型不匹配自然无法触发放置逻辑。 - 自定义mock的
dataTransfer对象残缺,缺少拖拽逻辑依赖的坐标、权限标识等属性,就算页面监听原生拖放事件,也会因为对象不符合规范拦截drop动作。 - 事件触发逻辑不符合真实交互:真实拖拽过程中会连续触发多次
dragover,且所有事件都携带准确的坐标信息;另外浏览器默认会阻止非拖拽允许区域的drop动作,必须在dragover阶段调用preventDefault()才能放行drop事件,现有代码完全没做这步。 - 直接通过JS派发的合成事件
isTrusted属性为false,部分前端安全策略会直接拦截这类非用户真实操作触发的事件。
可行方案
方案1:模拟真实鼠标操作(优先选择,适配90%以上Canvas场景)
放弃自定义JS触发drag事件的思路,直接用SeleniumLibrary自带的鼠标关键字,模拟真实用户拖拽的完整轨迹,不要直接从起点瞬移到终点:
*** Keywords *** Canvas Drag And Drop [Arguments] ${source_locator} ${target_locator} # 获取起点、终点的中心坐标 ${src_x} ${src_y} Get Center Coordinate ${source_locator} ${tgt_x} ${tgt_y} Get Center Coordinate ${target_locator} # 鼠标按下起点元素 Mouse Down ${source_locator} # 先移动到两点中点,模拟真实拖拽轨迹,避免被碰撞检测判定为无效 ${mid_x} Evaluate (${src_x} + ${tgt_x}) // 2 ${mid_y} Evaluate (${src_y} + ${tgt_y}) // 2 Mouse Move ${mid_x} ${mid_y} Sleep 0.1 # 移动到终点位置 Mouse Move ${tgt_x} ${tgt_y} Sleep 0.1 # 鼠标抬起完成放置 Mouse Up ${target_locator} Get Center Coordinate [Arguments] ${locator} ${rect} Get Element Rectangle ${locator} ${x} Evaluate ${rect['x']} + ${rect['width']} // 2 ${y} Evaluate ${rect['y']} + ${rect['height']} // 2 RETURN ${x} ${y}
如果必须用JS实现,就派发携带正确坐标的鼠标事件,替换原来的DragNDrop方法:
var DragNDrop = function(srcXpath, tgtXpath) { function getElementByXpath(path) { return document.evaluate(path, document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue; } const src = getElementByXpath(srcXpath); const tgt = getElementByXpath(tgtXpath); const srcRect = src.getBoundingClientRect(); const tgtRect = tgt.getBoundingClientRect(); // 计算轨迹点:起点、中点、终点 const points = [ {x: srcRect.left + srcRect.width/2, y: srcRect.top + srcRect.height/2}, {x: (srcRect.left + srcRect.width/2 + tgtRect.left + tgtRect.width/2)/2, y: (srcRect.top + srcRect.height/2 + tgtRect.top + tgtRect.height/2)/2}, {x: tgtRect.left + tgtRect.width/2, y: tgtRect.top + tgtRect.height/2} ]; // 鼠标事件派发工具 function emitMouse(type, point) { const evt = new MouseEvent(type, { clientX: point.x, clientY: point.y, bubbles: true, cancelable: true, button: 0, buttons: type === 'mousedown' || type === 'mousemove' ? 1 : 0 }); const el = document.elementFromPoint(point.x, point.y); el.dispatchEvent(evt); return evt; } // 按顺序触发事件 emitMouse('mousedown', points[0]); emitMouse('mousemove', points[1]); emitMouse('mousemove', points[2]); // 必须阻止dragover默认行为,否则浏览器不会触发drop const dragOverEvt = new DragEvent('dragover', { clientX: points[2].x, clientY: points[2].y, bubbles: true, cancelable: true }); dragOverEvt.preventDefault(); tgt.dispatchEvent(dragOverEvt); emitMouse('mouseup', points[2]); return true; }
方案2:修复原生HTML5拖放逻辑(仅适配绑定了原生拖放事件的Canvas场景)
如果确认Canvas绑定的是原生HTML5拖放事件,针对现有代码做4处修改即可:
- 删掉自定义mock的
dataTransfer对象,直接用DragEvent构造函数创建事件,使用原生自带的dataTransfer,避免属性缺失 - 所有事件初始化时传入正确的坐标、按键等参数,不要创建空事件直接派发
dragover事件触发后必须调用preventDefault(),浏览器默认会拦截未声明允许放置区域的drop动作- 增加2-3次中间点的
dragover事件触发,模拟真实拖拽移动过程,避免被页面碰撞检测拦截
注意:优先使用Selenium原生鼠标关键字操作,JS合成事件的
isTrusted属性为false,部分带前端安全校验的页面会直接拦截这类事件,怎么改JS都不会生效。
内容的提问来源于stack exchange,提问作者Smitha Bn
相关产品推荐
相关产品推荐

