webview使用
webview开启
在BrowserWindow实例化时,在webPreferences
配置中配置webviewTag:true
webview初始化
webview标签使用时,应使用默认src
属性为about:blank
这样不会使webview
因为没有初始化造成报错。随后可以根据src
属性动态修改指向。
webview预加载
我们可以通过预加载preload
的方式,通过注入js文件到webview中,从而达到干预内部网页行为的目的。
A
String
that 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 thewebPreferences
specified to thewill-attach-webview
event.
这里我们通过配置来进行预加载,这里有四点需要注意
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.js
const { 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.js
this.instance.addEventListener('ipc-message', event => {
const [keyWord] = event.args
this._dispatch('navigate-in-webview', keyWord)
})
webview.vue
this.webviewController.registerEvent('navigate-in-webview', (...args) => {
const [targetId] = args
// search from cache catalog and then navigate
const { linkId } = this.catalogFlatten.find(item =>
item.linkId.includes(targetId)
)
this.getCatalogById(linkId).then(res => {
if (res) {
// controll side behavior the same to located node
this.$emit('sync-side-bar', linkId)
}
})
})
视频文件加载错误问题
使用vue-cli-plugin-electron-builder
插件时,会造成视频文件加载错误,这里我们通过配置一个代理的静态端口 protocal,由主进程来处理。vue-cli-plugin-electron-builder中protocol来加载静态图片的例子
background.js
function registerLocalVideoProtocol () {
protocol.registerFileProtocol('local-video', (request, callback) => {
const url = request.url.replace(/^local-video:\/\//, '')
const decodedURL = decodeURI(url)
try {
// eslint-disable-next-line no-undef
return callback(path.join(__static, decodedURL))
} catch (error) {
console.error('could not get file path:', error)
}
})
}
.然后在视频文件上,使用local-video://
即可。github上作者的issues