electron之使用webview实现加载第三方网站

先看效果

功能说明

1、electron开发的程序中在一个modal里实现浏览外部网站

2、实现简单浏览以及简单控制(前进 后退 刷新 最小化 关闭),没有加地址部分的控制

技术

1、webview的嵌入和使用

2、点击链接打开新窗口时如何控制使新页面在当前窗口显示

有三种方式可以让你在electronBroweserWindow里集成(第三方)web内容,<iframe> 和, <webview>BrowserViews 每个功能都略有不同,适用于不同的情况 本文使用的是<webview>

webView是一个自定义元素 <webview>,仅在 Electron 内工作。在一个独立的 frame 和进程里显示外部 web 内容,这意味着所有与 <webview> 的通信都是异步使用 IPC 进行的。

启用webview

默认情况下,Electron >= 5禁用 webview 标签。 在构造 BrowserWindow 时,需要通过设置 webviewTag webPreferences选项来启用标签

页面代码

tsx 复制代码
import { useState } from 'react'
import WebviewItem from './components/WebviewItem'
import { Modal } from 'antd'

function App(): JSX.Element {
  const [modalOpen, setModalOpen] = useState(false)
  const [destroyChild, setDestroyChild] = useState(false)
  const url = 'https://juejin.cn/'

  const handleClose = (bol: boolean): void => {
    setModalOpen(false)
    setDestroyChild(bol)
  }
  
  return (
    <div>
       <div className="icon-box" onClick={(): void => setModalOpen(true)}>
          <span>掘金</span>
       </div>
       <Modal
        width={'100vw'}
        open={modalOpen}
        wrapClassName="desktop_setting_modal"
        style={{
          maxWidth: '100vw',
          height: '100vh',
          overflow: 'hidden',
          position: 'fixed',
          top: 0
        }}
        closable={false}
        destroyOnClose={destroyChild} //modal关闭时是否销毁子元素
        footer={null}
       >
        <WebviewItem handleClose={handleClose} src={url} />
      </Modal>
    </div>
  )
}

export default App

App.tsx中通过回调函数传过来的值 来设置Modal destroyOnClose属性值 从而实现网站的关闭 最小化

WebviewItem.tsx 完整代码

tsx 复制代码
import React, { useState, useEffect } from 'react'
import '../styles/WebviewItem.css'

interface IProp {
  src: string
  handleClose: (bol: boolean) => void
}

const WebviewItem: React.FC<IProp> = (props) => {
  const [src, setSrc] = useState(props.src)

  useEffect(() => {
    setSrc(src)
    // 获取webview元素
    const webview = document.getElementById(`webview-box${src}`) as HTMLIFrameElement | any

    if (!webview) return

    const buttons: HTMLButtonElement[] = [
      document.getElementById(`last-btn${src}`) as HTMLButtonElement,
      document.getElementById(`next-btn${src}`) as HTMLButtonElement,
      document.getElementById(`reload-btn${src}`) as HTMLButtonElement,
      document.getElementById(`minimize-btn${src}`) as HTMLButtonElement,
      document.getElementById(`close-btn${src}`) as HTMLButtonElement
    ]

    function handleNewWindow(e): void {
      const urlClass = new URL(e.url)
      const { protocol } = urlClass
      if (protocol === 'http:' || protocol === 'https:') {
        //更新当前url
        webview.src = e.url
      }
    }

    function updateButtonStatus(): void {
      buttons[0].disabled = !webview.canGoBack() // 禁用返回按钮,如果不能后退
      buttons[1].disabled = !webview.canGoForward() // 禁用后退按钮,如果不能前进
    }

    function handleButtonClick(event: Event): void {
      const buttonId = (event.target as HTMLElement).id
      switch (buttonId) {
        case `last-btn${src}`:
          if (webview.canGoBack()) {
            webview.goBack()
          }
          break
        case `next-btn${src}`:
          if (webview.canGoForward()) {
            webview.goForward()
          }
          break
        case `reload-btn${src}`:
          webview.reload()
          break
        case `minimize-btn${src}`:
          //通知父组件需要关闭Modal,但不需要销毁当前组件
          props.handleClose(false)
          break
        case `close-btn${src}`:
          //通知父组件需要关闭Modal,需要销毁当前组件
          props.handleClose(true)
          break
        default:
          break
      }
    }

    //webview 元素必须已被加载
    webview.addEventListener('dom-ready', updateButtonStatus)
    //监听网页打开新窗口
    webview.addEventListener('new-window', handleNewWindow)

    buttons.forEach((button) => {
      //给toolbar 5个按钮添加点击事件
      button.addEventListener('click', handleButtonClick)
    })
  }, [src])

  const customStatusbarHtml = `
    <div id="custom-statusbar">
      <div class="reload-box">
        <button id="last-btn${src}" disabled>回退</button>
        <button id="next-btn${src}" disabled>前进</button>
        <button id="reload-btn${src}">刷新</button>
      </div>
      <div class="button-box">
        <button id="minimize-btn${src}">最小化</button>
        <button id="close-btn${src}">关闭</button>
      </div>
    </div>
    <webview allowpopups src="${src}" id="webview-box${src}" class="webview-box"></webview>
  `
  return (
    <div
      dangerouslySetInnerHTML={{ __html: customStatusbarHtml }}
      style={{ width: '100vw', height: '100vh' }}
    />
  )
}

export default WebviewItem

WebviewItem.tsx代码中 使用了React dangerouslySetInnerHTML显示文本内容
<webview>标签:

1、src属性表示可见网址的string 更新src的值将重新加载页面

2、当我们点击所有 target 为 _blank 的 a 标签点击都没反应: 这是因为 webview 默认不允许打开新窗口,需要设置 allowpopups 属性

3、当我们设置allowpopups属性后,点击target 为 _blank 的 a 标签这时 electron应用程序会自动新开启BrowserWindow, 如果阻止默认行为,则需要在当前窗口主进程中监听web-contents-created事件

ts 复制代码
//阻止打开新窗口
  app.on('web-contents-created', (_, contents) => {
    contents.addListener('new-window', (e) => {
      e.preventDefault()
    })
  })

并且还可以在webview元素上监听新窗口 webview.addEventListener('new-window', handleNewWindow) 拿到新的url 更新(代码32行)

tips:app.on('web-contents-created') 优先webview.addEventListener('new-window')

好啦,功能完成了🍗

另外2种方法也可以实现,大家可以都试试,欢迎指点~

相关推荐
并不会28 分钟前
常见 CSS 选择器用法
前端·css·学习·html·前端开发·css选择器
衣乌安、31 分钟前
【CSS】居中样式
前端·css·css3
兔老大的胡萝卜31 分钟前
ppk谈JavaScript,悟透JavaScript,精通CSS高级Web,JavaScript DOM编程艺术,高性能JavaScript pdf
前端·javascript
低代码布道师34 分钟前
CSS的三个重点
前端·css
耶啵奶膘2 小时前
uniapp-是否删除
linux·前端·uni-app
王哈哈^_^4 小时前
【数据集】【YOLO】【目标检测】交通事故识别数据集 8939 张,YOLO道路事故目标检测实战训练教程!
前端·人工智能·深度学习·yolo·目标检测·计算机视觉·pyqt
cs_dn_Jie4 小时前
钉钉 H5 微应用 手机端调试
前端·javascript·vue.js·vue·钉钉
开心工作室_kaic5 小时前
ssm068海鲜自助餐厅系统+vue(论文+源码)_kaic
前端·javascript·vue.js
有梦想的刺儿5 小时前
webWorker基本用法
前端·javascript·vue.js
cy玩具5 小时前
点击评论详情,跳到评论页面,携带对象参数写法:
前端