uniapp的vue页面和非全屏webview交换数据的方式

在uniapp开发中,有时候我们需要在vue页面中嵌入一个webview组件,用来加载一些本地或远程的网页。但是,如何在vue页面和webview之间实现数据的传递和通信呢?常用的方法是使用uniapp官方提供的组件webview ,使用uni-app提供的UniAppJSBridgeReady事件和postMessage方法,来实现vue页面和webview之间的双向数据交换。但是这种方法有一定的局限性,webview组件设置的宽高等样式只有h5有效,在app中显示只能全屏加载,无法在app中实现vue页面和webview同屏交互,本文将介绍另一种自建webview的方法,可以在app中自定义webview的宽高及显隐。

首先,我们需要在vue页面中自建一个webview组件,代码如下,下面的代码自建了webview,并且完成了vue页面对html页面数据的接收和发送:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
<template>
</template>
<script>
export default {
data() {
return {
topHeight: 0,
windowHeight: 0,
url: "/hybrid/html/test.html",
fun: null,
}
},
methods: {
//初始化
init() {
// 获取系统信息,用于设置webview位置
var _this = this;
uni.getSystemInfo({
success: function(res) {
_this.topHeight = res.statusBarHeight
_this.windowHeight = res.windowHeight
}
})
// #ifdef APP-PLUS
//自建webview
//如果当前的文件为直接在pages.json声明的vue文件使用this.$scope.$getAppWebview(),
//如果当前的文件为pages.json声明的vue文件引用的子组件,使用this.$parent.$scope.$getAppWebview()
var currentWebview = this.$parent.$scope.$getAppWebview();
var height = this.windowHeight - this.topHeight;
wv = plus.webview.create(this.url, "webview", {
// plusrequire: "none", //注释后会无法使用数据交换,请勿放开注释
// 'uni-app': 'none',//注释后会无法使用数据交换,请勿放开注释
top: this.topHeight + 20,//根据你想要的样式设置top
scalable: true,//缩放
width: '100%',//根据你想要的样式设置宽度
height: height - 202//根据你想要的样式设置高度

})
currentWebview.append(wv);
//监听子html页面uni.postMessage返回的值,html页面触发plusMessage事件时会自动调用fun函数,实现对html页面返回值的接收和利用
let that = this
this.fun = function(msg) {
if (msg.data.args.data.name == 'postMessage') {
let msgData = msg.data.args.data.arg
console.log('app接收到消息为:' + JSON.stringify(msgData));

}
}
plus.globalEvent.addEventListener('plusMessage', this.fun);
// #endif
},
//调用该函数关闭webview渲染
close() {
// #ifdef APP-PLUS
if (wv) {
plus.webview.close(wv);
wv = null
}
// #endif
},
// 发送数据给html页面,本质上是执行了plus渲染的wv上携带的eval() 函数,下面的getData就是html页面要声明的getData函数,通过这种方法传递数据给html页面
evalJs(msg = "来自vue页面的参数") {
// #ifdef APP-PLUS
let str = `getData(${JSON.stringify(msg)})`
if (wv) {
wv.evalJS(str);
}
// #endif
}
}
}
</script>
<style>
</style>

接下来,我们需要在html页面中监听UniAppJSBridgeReady事件,这个事件会在webview加载完成后触发。在这个事件的回调函数中,我们可以获取到webview的对象,然后调用它的postMessage方法,向网页发送数据。这里我们假设要发送的数据是一个字符串”Hello, webview!”。代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport"
content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" />
<title>map</title>
<style type="text/css">
html,
body {
height: 100%;
margin: 0;
overflow: hidden;
}
</style>
<!-- 重要,引入了才能交互数据,具体文件可以在uniapp官网下载 -->
<script src="./js/uni.webview.1.5.4.js"></script>

</head>
<body>
<button id="postData">给app的页面发送数据</button>
</body>
<script>
//组件通信
//发送数据到vue组件
//UniAppJSBridgeReady事件会在uni.webview.js相关代码加载完成后触发,触发后就可以使用postMessage方法发送数据,一般可以在这个事件里调用一次postMessage来判断代码是否正常运行.
document.addEventListener('UniAppJSBridgeReady', function() {
let message = {
action: 'hello world'
}
uni.postMessage({
data: message
});
});
//自定义按钮数据发送
let btn = document.getElementById("postData")
btn.addEventListener("click", (e) => {
uni.postMessage({
data: {
action: "Hello, webview!", // 这是传的参数
},
});
})
//接收vue组件的数据
window.getData = function(msgList) {
console.log('接收vue组件传递来的数据:' + JSON.stringify(msgList));
}
</script>
</html>

总结一下,使用webview组件时,我们可以利用evalJS方法和postMessage方法,来实现vue页面和webview之间的双向数据交换。这样,我们就可以在uniapp中灵活地使用webview组件,来加载一些本地或远程的网页,并与它们进行通信,如果需要的就是全屏加载webview,那就不必使用本文的方法了,webview组件使用更方便一些,但是如果你需要更复杂的交互,还是自建webview更合理一些。


uniapp的vue页面和非全屏webview交换数据的方式
https://xiyu.pro/2023/06/03/27/
作者
Xi Yu
发布于
2023年6月3日
许可协议