问题

最近在用Electron中使用webview时发现当激活touch模式后,如果鼠标先点击了webview以外的区域使得焦点不在webview中,再回到webview时第一次点击无效。
示例图
在Electron的issue中搜了一下发现这竟然又是一个从第一个版本到现在一直存在的Bug。

规避方案

既然Electron没有提供可以解决这个问题的方法,那就只能想办法规避这种情况了。
在webview的页面中增加对touchstart、touchmove、touchend的监听后发现:

    window.addEventListener('touchend', (e) => {console.log('touchend', e)})
    window.addEventListener('touchmove', (e)=>{console.log('touchmove', e)})
    window.addEventListener('touchstart',(e)=>{console.log('touchstart', e);})

第一次在webview中点击时控制台的打印
页面只监听到了鼠标左键按下(touchstart),后续的鼠标移动和鼠标左键弹起都没有被响应。

这说明一定是由于什么原因导致后续事件被中断了,但是在这次touchstart之后,app中的焦点已经被定位在webview中,所以后续的鼠标操作不会再有问题。

因此我这里提供的规避这个问题的办法就是在每次重新点击webview时,再模拟产生一次鼠标按下的情况,让后续流程可以接上。

  // 主进程main.js
  const { ipcMain, webContents } = require('electron')
  ipcMain.on('touchstart', (e, msg) => {
  	// 这里是通过title找到webview对应的webContent,我的示例中webview加载的文件名是test.html
    const webContent = webContents.getAllWebContents().find(item => item.getTitle() === 'test.html')
    if (webContent) {
      // 向对应webview发送mouseDown(也就是touchstart)事件
      webContent.sendInputEvent({
        ...msg,
        type: 'mouseDown', 
        button: 'left',
        clickCount: 1
      });
    } else {
      console.log('error')
    }
  })
	// 渲染进程test.html
    const { ipcRenderer } = require('electron')
    // 用来模拟焦点是否在当前页面上
    let isFocus = false
    setInterval(() => {
      console.log('焦点已不在区域内')
      isFocus = false
    }, 10000)
    window.addEventListener('touchstart',(e)=>{
      console.log('touchstart', e); 
      // 当监听到touchstart时,判断如果之前焦点不在当前webview,那向主进程发送模拟鼠标按下事件的消息
      if (!isFocus) {
        isFocus = true
        ipcRenderer.send('touchstart', {x: e.touches[0].clientX, y: e.touches[0].clientY})
      }
    })

修改后再次点击webview时发现:
模拟touchstart的情况
控制台上打印了两次start,一次end。
第一次start时自动激活了webview的焦点,我们再手动触发一次start
第二次start也就是我们在主进程发送的mouseDown事件
打印的end是我们在松开鼠标时打印的内容。

touchmove也是可以的
touchmove
不过由于会多一次start事件,因此如果业务中对start有额外的逻辑,需要做特殊处理。

另外在示例中是模拟了焦点标志位的变化,实际中需要在外层页面和webview中增加第一次被点击时通知主进程焦点转移的逻辑,再由主进程通知每个webContent当前焦点在哪。

目前想到的这种方法只是一种替代的方案,如果有其他更好的方法,烦请告知,感激不尽。

Logo

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。

更多推荐