Skip to main content
席宇博客

欢迎访问席宇博客

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页面数据的接收和发送:

<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!"。代码如下:

<!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更合理一些。