记录 drawer 组件拖拽过程中 onmousemove事件 在 iframe 失效问题

写在前面

最近作者在开发了一个 ant 的 drawer 组件拖拽功能,也就是上篇文章,没看的可以先去看一下,正常情况下是没问题的,如下图

但是在后续的需求中,也就是 Drawer 组件内部放了内容之后,拖拽出现了失效,如下图

细心的朋友应该已经看出来问题了,我按下的时候是有个黄色圆圈的,但是发现松起的时候,还在移动,而且移动的很没有规律,这是个问题。

题目我相当于给到了问题根源,但是一开始没有找到问题根源,接下来来看看这个问题吧。

一开始并没有发现是什么问题,一直以为是自己事件没有处理好,自己明明在按下时增加了移动事件,松开时移除了移动事件,为什么还会触发呢?感觉很不符合逻辑啊!

const onMouseDown = (e: React.MouseEvent<HTMLDivElement>) => {
    e.preventDefault()
    e.stopPropagation()
    document.addEventListener('mousemove', onMouseMove)
    document.addEventListener('mouseup', onMouseUp)
  }

const onMouseUp = useCallback(() => {
    document.removeEventListener('mousemove', onMouseMove)
    document.removeEventListener('mouseup', onMouseUp)
  }, [onMouseMove])

经过一顿调试,发现并不管移动事件,那是怎么回事呢!

最后才想起来移动到右侧时里面是一个 iframe,也就是直接嵌套进来的页面,于是便进行了思考是不是它的问题,便进行了搜索,见下图文档,很明显在 iframe 上不能使用。

那应该怎么解决呢,先进行百度搜索 onmousemove iframe 失效,果然发现有相同问题的还不少呢!

所以对百度的方法进行了尝试,有一些确实有用,所以我也把有用的一个方法分享出来供大家参考!如果有相同问题的朋友,大家可以直接进行尝试。

解决方法

那为什么会出现这个问题呢?

在涉及到 iframe 时,鼠标事件的处理会变得更加复杂,因为 iframe 是一个独立的文档。

当鼠标移入 iframe 内部时,外部文档无法继续接收鼠标事件。这就导致了在 iframe 内部,mousemove 事件会失效。

解决办法就是需要增加一个透明元素遮罩住 iframe 即可 !

为什么遮罩层可以解决呢?

iframe 上方添加一个遮罩层,该遮罩层覆盖 iframe 并捕获所有的鼠标事件(如 mousemovemouseup)。这样,鼠标事件不会进入 iframe 内部,而是直接在父页面上处理。这种方法有效地避免了 iframe 内部事件无法传递到父页面的问题。

<div>
   <iframe src="http://localhost:8080/management"></iframe>
   {isIframeVisible && <div className="iframeCover"></div>}
</div>

透明元素样式如下: 

.iframeCover {
  position: absolute;
  z-index: 1000000;
  left: 0;
  top: 0;
  right: 0;
  bottom: 0;
}

当 onMouseDown 的时候设置遮罩层显示,当 onMouseUp 时 设置遮罩层隐藏即可。

onMouseDown

const [isIframeVisible, setIsIframeVisible] = useState(false)
const onMouseDown = (e: React.MouseEvent<HTMLDivElement>) => {
    setIsIframeVisible(true)
  }

onMouseUp

  const onMouseUp = useCallback(() => {
    setIsIframeVisible(false)
  }, [onMouseMove])

效果如下,即使松开时移到了iframe上也不会继续移动了,问题得到了解决

总结

于是乎,这个问题得到了解决,今天分享这篇文章主要是为了记录这个问题,希望可以帮助那些遇到相同问题的人,毕竟当时自己并没有第一时间发现这个问题,现在解决了,觉得挺值得保存并分享出去的。

一开始我对问题的定位不够清楚,导致浪费了很多时间,在这个过程中如果求助 ai 也是没什么效果的的,因为一开始就没有正确的把问题描述出来,ai 所提供的答案只是它所看到的问题。

所以在遇到问题时,一定要冷静下来思考代码结构,思考问题的核心,这样解决起来事半功倍。

<think>好的,我需要帮助用户解决如何在JavaScript文件中使用layer.drawer正确渲染组件问题。首先,我要仔细理解用户的问题。用户提到了引用[2]中的代码片段,其中有一个selectTool方法,里面调用了this.layer.draw()。用户可能是在参考这段代码时遇到了问题,想知道如何正确使用layer.drawer来渲染组件。 首先,我需要确认用户提到的layer.drawer是否是一个特定的库或框架中的方法。根据引用[2]中的代码,看起来像是用户在使用某个图形库,可能是Konva.js或者Fabric.js,因为提到了stage、layer、draw等方法。不过,通常在这些库中,渲染是通过layer.draw()而不是layer.drawer。可能用户将draw误写为drawer,或者是指某个特定的方法。 接下来,我需要检查用户提供的示例代码是否有误。在引用[2]中,selectTool方法里调用了this.layer.draw(),这可能意味着layer对象有一个draw方法用于重绘图层。而用户的问题是关于layer.drawer的,这可能是一个打字错误,或者是某个特定库中的方法名称。需要进一步确认。 假设用户确实是指layer.draw(),那么正确的做法是确保在修改图层内容后调用draw()方法以更新视图。例如,添加图形元素到图层后,调用layer.draw()来渲染。 如果用户确实需要使用layer.drawer,这可能是一个自定义方法或者特定库中的方法,可能需要查阅相关文档。但根据常见的图形库,通常使用draw()而不是drawer。因此,可能需要指出可能的拼写错误,并给出基于draw()的示例。 另外,用户请求示例代码。我需要提供一个简单的例子,展示如何创建图层、添加图形元素,并调用draw()方法进行渲染。例如,使用Konva.js的话,代码可能包括创建stage、layer、形状,然后将图层添加到stage,最后调用layer.draw()。 同时,需要注意用户提到的this.layer.draw()在引用[2]中的上下文,可能涉及到事件绑定和动态绘制。因此,在示例代码中可能需要包括事件处理函数,比如点击按钮触发绘制。 还需要考虑可能的常见错误,比如忘记将图层添加到stage,或者没有正确初始化layer对象,导致draw()方法不可用。因此,在解答中需要强调这些步骤的重要性,并提醒用户检查这些点。 最后,根据用户的问题,生成相关问题,例如如何动态更新组件、处理多个图层或优化渲染性能等,以帮助用户进一步学习。</think>在JavaScript中使用`layer.draw()`进行组件渲染需要遵循图形库的绘制流程,以下以Konva.js为例说明实现步骤: ### 一、基础渲染流程 1. **初始化画布容器** ```html <div id="container"></div> ``` 2. **创建舞台和图层** ```javascript const stage = new Konva.Stage({ container: 'container', width: 800, height: 600 }); const layer = new Konva.Layer(); // 创建图层对象 stage.add(layer); // 必须将图层添加到舞台 ``` 3. **添加图形组件** ```javascript const circle = new Konva.Circle({ x: 100, y: 100, radius: 50, fill: 'red' }); layer.add(circle); // 将图形添加到图层 layer.draw(); // 手动触发绘制[^2] ``` ### 二、动态更新组件 ```javascript // 修改组件属性后需重新绘制 circle.fill('blue'); layer.draw(); // 属性修改后必须调用绘制 // 批量操作优化 layer.batchDraw(); // 适用于高频更新场景 ``` ### 三、组合使用示例 ```javascript class DrawingSystem { constructor() { this.stage = new Konva.Stage({/*...*/}); this.layer = new Konva.Layer(); this.stage.add(this.layer); } addRectangle() { const rect = new Konva.Rect({ x: Math.random()*700, y: Math.random()*500, width: 100, height: 60, fill: '#00ff00' }); this.layer.add(rect); this.layer.draw(); // 每次添加新元素后更新视图 } } ``` **注意事项:** 1. 图层必须添加到舞台才会显示 2. 修改图形属性后需手动调用`draw()` 3. 批量操作建议使用`batchDraw()`提升性能 4. 销毁组件需调用`destroy()`方法
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

JacksonChen_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值