webview使用
webview开启
在BrowserWindow实例化时,在webPreferences配置中配置webviewTag:true
webview初始化
webview标签使用时,应使用默认src属性为about:blank这样不会使webview因为没有初始化造成报错。随后可以根据src属性动态修改指向。
webview预加载
我们可以通过预加载preload的方式,通过注入js文件到webview中,从而达到干预内部网页行为的目的。
A
Stringthat specifies a script that will be loaded before other scripts run in the guest page. 该脚本的URL的协议必须是file:asar:二者之一,因为在访客页中,它是通过“内部”的require去加载的 当访客页没有 node integration ,这个脚本仍然有能力去访问所有的 Node APIs, 但是当这个脚本执行执行完成之后,通过Node 注入的全局对象(global objects)将会被删除。 Note: This option will appear aspreloadURL(notpreload) in thewebPreferencesspecified to thewill-attach-webviewevent.
这里我们通过配置来进行预加载,这里有四点需要注意
mac、linux系统需要加上file://这样的protocol- 在配置中我们需要改变的字段是
preloadURL而不是preload - 需要将需要预加载的js文件放到插件为我们暴露的
__static路径中,他指向了public/ - 事件的注入钩子,需要使用
will-attacj-webview在这个钩子中响应
webview预加载JS与渲染进程通信
我们通过外部注入webview中的网页需要和渲染进程通信,得益于electron的强大功能,在预加载的JS中,我们可以通过其内部的require方法,拿到ipcRenderer以及其他我们可以使用的API,但是这些都会在加载网页完成后被移除。
该脚本的URL的协议必须是
file:asar:二者之一,因为在访客页中,它是通过“内部”的require去加载的当访客页没有 node integration ,这个脚本仍然有能力去访问所有的 Node APIs, 但是当这个脚本执行执行完成之后,通过Node 注入的全局对象(global objects)将会被删除。
具体内容,请参考这里。这里,一个小例子,我们使用 ipcRenderer.sendToHost来发送事件,修改webview嵌入页面的跳转事件。
//preload.jsconst { ipcRenderer } = require('electron')document.addEventListener('DOMContentLoaded', () => {blanketHrefOriginalBehavior()})// 修改A标签原有href,代理点击事件到外层通信// 阻止默认跳转事件,改由IPC代理至渲染进程处理const blanketHrefOriginalBehavior = () => {const aTag = document.querySelectorAll('a')Array.from(aTag).forEach(tag => {const href = tag.getAttribute('href')const title = tag.getAttribute('title')if (href && !href.includes('#') && title) {tag.addEventListener('click', e => {e.preventDefault()ipcRenderer.sendToHost('navigate-in-webview', title)})}})}
在外部渲染进程的页面中,我们使用webview.addEventListeners('ipc-message')来接收。然后发送这个事件到vue的组件中
webviewController.jsthis.instance.addEventListener('ipc-message', event => {const [keyWord] = event.argsthis._dispatch('navigate-in-webview', keyWord)})
webview.vuethis.webviewController.registerEvent('navigate-in-webview', (...args) => {const [targetId] = args// search from cache catalog and then navigateconst { linkId } = this.catalogFlatten.find(item =>item.linkId.includes(targetId))this.getCatalogById(linkId).then(res => {if (res) {// controll side behavior the same to located nodethis.$emit('sync-side-bar', linkId)}})})
视频文件加载错误问题
使用vue-cli-plugin-electron-builder插件时,会造成视频文件加载错误,这里我们通过配置一个代理的静态端口 protocal,由主进程来处理。vue-cli-plugin-electron-builder中protocol来加载静态图片的例子
background.jsfunction registerLocalVideoProtocol () {protocol.registerFileProtocol('local-video', (request, callback) => {const url = request.url.replace(/^local-video:\/\//, '')const decodedURL = decodeURI(url)try {// eslint-disable-next-line no-undefreturn callback(path.join(__static, decodedURL))} catch (error) {console.error('could not get file path:', error)}})}
.然后在视频文件上,使用local-video://即可。github上作者的issues
