Interactjs在Ionic+Vue项目中移动端拖拽克隆元素时出现读取'left'的TypeError错误
问题根因
- 你当前的报错核心是
interaction.start传入的第二个参数event.interactable和第三个参数element不匹配:当原始元素无transform属性时,逻辑进入克隆分支,传入start的element是新生成的克隆节点,但event.interactable是绑定在原始拖拽元素上的实例,interact.js内部校验不匹配直接抛出错误,你给原始元素加transform后逻辑进入else分支,传入的element就是原始元素,和interactable匹配因此报错消失。 - 移动端触摸事件的
move触发频率远高于桌面端鼠标事件,你在高频触发的move回调中修改DOM、启动拖拽,交互状态同步不及时,进一步放大了不兼容问题,因此移动端必现、桌面端偶现。
解决方案
方案1:给克隆节点绑定对应interactable配置(最优)
把你绑定给原始拖拽元素的interact配置抽为公共变量,克隆节点生成后先绑定相同的interact配置,再调用start方法,完全匹配校验规则:
// 提前抽公共配置 const dragConfig = { // 你原来给原始元素绑定时的所有draggable配置,比如 inertia、modifiers 等 } // 原始元素绑定逻辑 interact('.origin-circle').draggable(dragConfig) const dragOrClone = (event) => { // ... 原有其他逻辑不变 if(/* 触发克隆的判断条件 */) { element = currentTarget.cloneNode(true); // ... 原有克隆节点样式设置逻辑不变 dropzone && dropzone.appendChild(element); // 新增:给克隆节点绑定相同的拖拽配置 interact(element).draggable(dragConfig) // ... 原有坐标重置逻辑不变 } // 调用start前替换为克隆节点对应的interactable实例 const targetInteractable = interact(element).interactable if(targetInteractable && interaction.pointerIsDown && !interaction.interacting()) { interaction.start({ name: "drag" }, targetInteractable, element); } }
方案2:调整触发时机优化稳定性
把克隆逻辑从高频触发的move回调移到down事件回调中处理,提前完成节点生成、配置绑定,move事件仅处理位移更新,大幅降低移动端兼容性问题:
// 新增down事件监听 interact('.origin-circle') .on('down', (event) => { const { currentTarget, interaction } = event if(currentTarget.style.transform === "") { // 把原来的克隆逻辑全移到这里处理,提前生成克隆节点、绑定配置、插入父容器 // 存储生成的克隆节点到全局变量,供后续move事件使用 window.clonedDragEl = 生成的克隆节点 } }) .on('move', dragOrClone) const dragOrClone = (event) => { const { interaction } = event // 直接用提前生成的节点启动拖拽,不需要再处理克隆逻辑 const element = window.clonedDragEl || event.currentTarget const targetInteractable = interact(element).interactable if(targetInteractable && interaction.pointerIsDown && !interaction.interacting()) { interaction.start({ name: "drag" }, targetInteractable, element); } // ... 原有位移更新逻辑 }
方案3:应急兼容方案
如果不想调整现有逻辑结构,可以在调用interaction.start前增加异步等待,等DOM状态同步完成后再启动拖拽,适合快速修复:
// 把原来的interaction.start调用替换为以下代码 setTimeout(() => { const targetInteractable = interact(element).interactable if(targetInteractable && interaction.pointerIsDown && !interaction.interacting()) { interaction.start({ name: "drag" }, targetInteractable, element); } }, 0)
额外优化建议
- 拖拽结束的
dragend事件中要记得销毁克隆节点的interact实例、移除DOM节点,避免内存泄漏和页面残留多余元素 - 开启interact.js的touchAction配置避免和移动端浏览器默认触摸行为冲突:
interact('.origin-circle').touchAction('none') - Ionic页面离开时要销毁所有绑定的interact实例,避免跨页面事件冲突
内容的提问来源于stack exchange,提问作者usanzadunje
相关产品推荐
相关产品推荐

