NewsNing
NewsNing
  • 发布:2018-01-18 11:25
  • 更新:2018-01-18 11:25
  • 阅读:4178

【5+】Webview页面之间的数据交流

分类:HTML5+

一个App,其中大部分是要对页面之间的数据进行交互。

123

碧如:A打开B页面,B页面执行一些代码,再通知回A页面。

这可能是h5+er们遇到最常见的一个场景了。

ok,我们将问题实例化:

A页面有个选择地区的按钮,需要打开B页面选择一个地区,然后获取到选取结果返回给A页面并展示。

我们看看用mui.fire怎么来实现这个功能

123

A页面

1

		<header class="mui-bar mui-bar-nav">  
		    <h1 class="mui-title">A</h1>  
		</header>  
		<div class="mui-content">  
			<input type="text" readonly placeholder="未选择">  
		    <button type="button" class="mui-btn mui-btn-blue">选取地区</button>  
		</div>  
		  
		<script src="js/mui.min.js"></script>  
		<script type="text/javascript">  
			mui.init();  
			// 自定义监听select事件  
			document.addEventListener('select', function(e){  
				var text = e.detail.text;  
				document.querySelector("input").value = text;  
			});  
			// 按钮点击事件  
			document.querySelector(".mui-btn-blue").addEventListener('tap', function(){  
				// 打开B页面,选取一个结果  
				mui.openWindow('B.html');  
			});  
		</script>

B页面

2

		<header class="mui-bar mui-bar-nav">  
			<a class="mui-action-back mui-icon mui-icon-left-nav mui-pull-left"></a>  
			<h1 class="mui-title">B</h1>  
		</header>  
		<div class="mui-content">  
			<ul class="mui-table-view">  
				<li class="mui-table-view-cell">  
					<a class="mui-navigate-right">  
						上海  
					</a>  
				</li>  
				<li class="mui-table-view-cell">  
					<a class="mui-navigate-right">  
						深圳  
					</a>  
				</li>  
				<li class="mui-table-view-cell">  
					<a class="mui-navigate-right">  
						北京  
					</a>  
				</li>  
			</ul>  
		</div>  
  
		<script src="js/mui.min.js"></script>  
		<script type="text/javascript">  
			mui.init();  
			mui('ul').on('tap', 'li', function() {  
				// 获取当前选择的内容  
				var text = this.innerText;  
				// 通知上个页面  
				var w = plus.webview.currentWebview();  
				var opener = w.opener();  
				mui.fire(opener, "select",{  
					text: text  
				});  
				// 关闭本页面  
				w.close();  
			});

真机调试一下,o98k。

3

但是!我个人还是建议脱离mui.js来实现这个功能

4

可以借用咱们之前文章里面的讲过的,利用webview对象的evalJS方法

【5+】跨webview多页面 触发事件(一)
【5+】跨webview多页面 触发事件(一)

感觉用Broadcast.js有点小题大做

5

那咱们就写一个类似Android中的onActivityResult和setResult方法

新建一个app.js,作为一个自己的插件,里面实现两个方法 onActivityResult 和 setResult

  
(function(app){  
	  
	/**  
	 * 打开一个页面  
	 * @param {String} url 页面路径  
	 * @param {String} id 页面id  
	 * @param {Object} ex 参数  
	 * @param {Function} callback   
	 */  
	app.onActivityResult = function(url, id, ex, callback){  
		  
	};  
	  
	/**  
	 * 返回创建者页面数据  
	 * @param {Object} data 需要返回的数据  
	 * @return {Webview} w 当前webview  
	 */  
	app.setResult = function(data){  
		  
	};  
	  
	  
}(window.app || (window.app = {})));  

我们一步步来,先看看setResult如何触发上个页面的函数

	/**  
	 * 返回创建者页面数据  
	 * @param {Object} data 需要返回的数据  
	 * @return {Webview} w 当前webview  
	 */  
	app.setResult = function(data){  
		// 获取当前webview  
		var indexW = plus.webview.currentWebview();  
		// 获取创建者的webview  
		var opener = indexW.opener();  
		// 执行js字符串  
		opener.evalJS();// ??????  
	};

卧槽,那么,问题来了,evalJS该执行什么呢?

如果我在A页面的window对象下定一个函数

window.test = function(data){  
    alert(JSON.stringify(data));  
}

那么,我们在evalJS里面就该这么写

		// 执行js字符串  
		var jsstr = "window.test && window.test(" + JSON.stringify(data) + ")";  
		opener.evalJS(jsstr); 

好吧,考虑到一个页面可能通过这个方式打开多个页面,那么我们这个test函数就得改一个不重复唯一的名称,并且定义放到onActivityResult方法里面

	var _id = 0,  
		_tempName = '',  
		ow,cw;  
  
		/**  
		 * 打开一个页面  
		 * @param {String} url 页面路径  
		 * @param {String} id 页面id  
		 * @param {Object} ex 参数  
		 * @param {Function} callback   
		 */  
		app.onActivityResult = function(url, id, ex, callback) {  
			  
			// 生成唯一回调函数名称  
			_tempName = 'APP_RESULT_FUN_' + _id++;  
			// 定义函数  
			window[_tempName] = function(data){  
				// 执行自定义回调  
				callback(data);  
			};  
			// 传递函数名称到目标页面  
			ex.callbackName = _tempName;  
			  
			// 显示菊花  
			cw = plus.nativeUI.showWaiting();  
			  
			// 创建目标页面   
			ow = plus.webview.create(url, id, {  
				render: "always"  
			}, ex);  
			// title更新时显示 页面  
			ow.addEventListener('titleUpdate', function(){  
				// 关闭菊花  
				cw && (cw.close(),cw = null);  
				// 显示页面  
				ow.show('pop-in');  
			});  
			// 页面关闭时,注销window下此次事件  
			ow.addEventListener('close', function(){  
                                setTimeout(function(){  
                                        window[_tempName] = null;  
                                });  
				  
			});  
			  
		};

生成特殊一个函数,并把函数名通过extras的方式传参到目标页面,
相应的,setResult方法也需要少许更改

	/**  
	 * 返回创建者页面数据  
	 * @param {Object} data 需要返回的数据  
	 * @return {Webview} w 当前webview  
	 */  
	app.setResult = function(data) {  
		// 获取当前webview  
		var indexW = plus.webview.currentWebview();  
		// js字符串  
		var jsstr = "";  
		// 如果存在自定义回调函数名  
		if(indexW.callbackName){  
			// 拼接js字符串  
			jsstr = "window." + indexW.callbackName;  
			jsstr = jsstr + "&&" + jsstr + "(" + JSON.stringify(data) + ")";  
			// 执行  
			indexW.opener().evalJS(jsstr);  
		}  
		// 返回当前页面  
		return indexW;  
	};

试试引用后在AB页面测试一下

			// A页面 按钮点击事件  
			document.querySelector(".mui-btn-blue").addEventListener('tap', function(){  
				// 打开B页面,选取一个结果  
				app.onActivityResult('B.html', 'B', {}, function(data){  
					// 修改内容  
					document.querySelector("input").value = data.text;  
				});  
			});  
              
            // B页面 选项点击事件  
            mui('ul').on('tap', 'li', function() {  
				// 获取当前选择的内容  
				var text = this.innerText;  
				// 通知上个页面 并关闭本页面  
				app.setResult({  
					text: text  
				}).close();  
			});

卧槽666。

class Man{  
    constructor(){  
        this.name = 'newsning'  
    }  
    say(){  
        console.log('天行健, 君子以自强不息. ')  
    }  
}
4 关注 分享
Trust lhyh BoredApe 赵梦欢

要回复文章请先登录注册

NewsNing

NewsNing (作者)

回复 赵梦欢 :
哈哈,配合Rx.js用起来很爽的
2018-01-19 11:56
赵梦欢

赵梦欢

不错的想法
2018-01-18 22:17
NewsNing

NewsNing (作者)

回复 lhyh :
多谢大佬捧场
2018-01-18 13:32
NewsNing

NewsNing (作者)

回复 小资电脑 :
大概就是mui.fire的原理以及脱离mui.js的情况啦
2018-01-18 13:32
lhyh

lhyh

宁大出品,必属精品
2018-01-18 12:32
小资电脑

小资电脑

没细看 :) 这么多内容 是不是太复杂了? 我直接用mui.fire搞定
2018-01-18 12:03