当前位置:   article > 正文

在uni-app里通过web-view组件显示H5项目的踩坑之旅_app内嵌h5页面webview

app内嵌h5页面webview

为啥要在uni-app去显示h5?

说起来话长,最近的项目需求里,有个图超级复杂,uni-app使用echarts之后在真机渲染不出来,但是在h5又可以渲染出来,而这个bug echarts开发者好像还没有修复。所以导致所在图表的一整个页面都只好用H5来实现了。
另外,使用这种方法还有另外一个优点,就是app的这个界面可以热更新,就不需要通过重新安装apk来进行更新了。
只不过,我遇到了很多的坑,后面会一一列出来的。

1.如何在uni-app上使用web-view组件渲染内外部的h5页面?

官网有虽然有教程,但我还是把自己代码铺出来,因为感觉有些地方新手可能会很迷惘。
这是官网的有关这个组件的地址:https://uniapp.dcloud.net.cn/component/web-view.html#web-view

①在uni-app上的页面使用web-view

<template>
  <view class="" style="width: 100%;">
    <web-view :src="url" @message ="message"></web-view>
  </view>
</template>
<script>
export default {
  data() {
    return {
      url:'http://localhost:8080/#/test' //这是本地运行的另一个vue项目的地址
    };
  },
  onReady() {  
     // #ifdef H5
     window.addEventListener("message", this.message, false)  //如果不加这句代码,真机运行的时候,就无法监听到message事件
     // #endif  
  },   
  methods: {
    message(event){
		console.log(event)
		// #ifdef APP-PLUS
		if(event.detail.data[0].action=='success'){
			console.log('当字段为success的时候,跳转页面')
			uni.navigateTo({
				url:'sleepLog/device'
			})
		}
		// #endif  
    }
  }
};
</script>
  • 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

② uni-app页面如何给H5发消息通信?

方法一:通过evalJS

首先在uni-app端,在页面加载完之后,增加一个全局函数,这个函数的声明放在methods里就好

  sendMsgToWebview() {
	 let _funName='msgFromUniapp'
	 let _data = {
	      msg:'refresh'
	    }
	 let currentWebview = this.$scope.$getAppWebview().children()[0];
	 currentWebview.evalJS(`${_funName}(${JSON.stringify(_data)})`)
},
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

然后可以在加载完dom之后的声明周期函数里使用,例如onReady

 onReady() {
  	  // #ifdef H5
     window.addEventListener("message", this.message, false)  
     // #endif  
	this.sendMsgToWebview()
  },
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

然后在h5端的mounted钩子函数里,加上

  mounted() {
		let that=this
		window.msgFromUniapp = function(arg) {
			//注意this指向
		if(arg.msg=='refresh'){
			console.log('shuaxin')
			//当uni-app发送这个refresh的时候,h5可以在这里监听并做想要做的事
		}
		}
  },
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
方法二:通过url携带参数

例如:
在uni-app的web-view上的url加上参数

 url:'http://localhost:8080'+'/#/index?token='+ uni.getStorageSync("accessToken")+'&userId='+getApp().globalData.global_user.id
  • 1

在h5上获取url上的参数,可以在钩子函数mounted里获取

	let token=window.location.href.split('?')[1].split('&')[0].split('=')[1]//这是拿到的第一个参数 token
	let userId=window.location.href.split('?')[1].split('&')[1].split('=')[1]//这是拿到的第二个参数  userid
  • 1
  • 2

当然,拿到的token也可以把它存到vuex,在这里我就不多说了。

2.如何在H5项目使用uni-app的sdk,从而让h5可以和uni-app进行相互通信?

①引入webview.js

我是新建了个目录和文件用来存webview.js
在这里插入图片描述
web.js如下:

! function (e, n) {
  "object" == typeof exports && "undefined" != typeof module ? module.exports = n() : "function" == typeof define && define.amd ? define(n) : (e = e || self).webUni = n()
}(this, (function () {
  "use strict";
  try {
    var e = {};
    Object.defineProperty(e, "passive", {
      get: function () {
        !0
      }
    }), window.addEventListener("test-passive", null, e)
  } catch (e) {}
  var n = Object.prototype.hasOwnProperty;

  function t(e, t) {
    return n.call(e, t)
  }
  var i = [],
    a = function (e, n) {
      var t = {
        options: {
          timestamp: +new Date
        },
        name: e,
        arg: n
      };
      if (window.__dcloud_weex_postMessage || window.__dcloud_weex_) {
        if ("postMessage" === e) {
          var a = {
            data: [n]
          };
          return window.__dcloud_weex_postMessage ? window.__dcloud_weex_postMessage(a) : window.__dcloud_weex_.postMessage(JSON.stringify(a))
        }
        var o = {
          type: "WEB_INVOKE_APPSERVICE",
          args: {
            data: t,
            webviewIds: i
          }
        };
        window.__dcloud_weex_postMessage ? window.__dcloud_weex_postMessageToService(o) : window.__dcloud_weex_.postMessageToService(JSON.stringify(o))
      }
      if (!window.plus) return window.parent.postMessage({
        type: "WEB_INVOKE_APPSERVICE",
        data: t,
        pageId: ""
      }, "*");
      if (0 === i.length) {
        var r = plus.webview.currentWebview();
        if (!r) throw new Error("plus.webview.currentWebview() is undefined");
        var d = r.parent(),
          s = "";
        s = d ? d.id : r.id, i.push(s)
      }
      if (plus.webview.getWebviewById("__uniapp__service")) plus.webview.postMessageToUniNView({
        type: "WEB_INVOKE_APPSERVICE",
        args: {
          data: t,
          webviewIds: i
        }
      }, "__uniapp__service");
      else {
        var w = JSON.stringify(t);
        plus.webview.getLaunchWebview().evalJS('UniPlusBridge.subscribeHandler("'.concat("WEB_INVOKE_APPSERVICE", '",').concat(w, ",").concat(JSON.stringify(i), ");"))
      }
    },
    o = {
      navigateTo: function () {
        var e = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {},
          n = e.url;
        a("navigateTo", {
          url: encodeURI(n)
        })
      },
      navigateBack: function () {
        var e = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {},
          n = e.delta;
        a("navigateBack", {
          delta: parseInt(n) || 1
        })
      },
      switchTab: function () {
        var e = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {},
          n = e.url;
        a("switchTab", {
          url: encodeURI(n)
        })
      },
      reLaunch: function () {
        var e = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {},
          n = e.url;
        a("reLaunch", {
          url: encodeURI(n)
        })
      },
      redirectTo: function () {
        var e = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {},
          n = e.url;
        a("redirectTo", {
          url: encodeURI(n)
        })
      },
      getEnv: function (e) {
        window.plus ? e({
          plus: !0
        }) : e({
          h5: !0
        })
      },
      postMessage: function () {
        var e = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {};
        a("postMessage", e.data || {})
      }
    },
    r = /uni-app/i.test(navigator.userAgent),
    d = /Html5Plus/i.test(navigator.userAgent),
    s = /complete|loaded|interactive/;
  var w = window.my && navigator.userAgent.indexOf("AlipayClient") > -1;
  var u = window.swan && window.swan.webView && /swan/i.test(navigator.userAgent);
  var c = window.qq && window.qq.miniProgram && /QQ/i.test(navigator.userAgent) && /miniProgram/i.test(navigator.userAgent);
  var g = window.tt && window.tt.miniProgram && /toutiaomicroapp/i.test(navigator.userAgent);
  var v = window.wx && window.wx.miniProgram && /micromessenger/i.test(navigator.userAgent) && /miniProgram/i.test(navigator.userAgent);
  var p = window.qa && /quickapp/i.test(navigator.userAgent);
  for (var l, _ = function () {
      window.UniAppJSBridge = !0, document.dispatchEvent(new CustomEvent("UniAppJSBridgeReady", {
        bubbles: !0,
        cancelable: !0
      }))
    }, f = [function (e) {
      if (r || d) return window.__dcloud_weex_postMessage || window.__dcloud_weex_ ? document.addEventListener("DOMContentLoaded", e) : window.plus && s.test(document.readyState) ? setTimeout(e, 0) : document.addEventListener("plusready", e), o
    }, function (e) {
      if (v) return window.WeixinJSBridge && window.WeixinJSBridge.invoke ? setTimeout(e, 0) : document.addEventListener("WeixinJSBridgeReady", e), window.wx.miniProgram
    }, function (e) {
      if (c) return window.QQJSBridge && window.QQJSBridge.invoke ? setTimeout(e, 0) : document.addEventListener("QQJSBridgeReady", e), window.qq.miniProgram
    }, function (e) {
      if (w) {
        document.addEventListener("DOMContentLoaded", e);
        var n = window.my;
        return {
          navigateTo: n.navigateTo,
          navigateBack: n.navigateBack,
          switchTab: n.switchTab,
          reLaunch: n.reLaunch,
          redirectTo: n.redirectTo,
          postMessage: n.postMessage,
          getEnv: n.getEnv
        }
      }
    }, function (e) {
      if (u) return document.addEventListener("DOMContentLoaded", e), window.swan.webView
    }, function (e) {
      if (g) return document.addEventListener("DOMContentLoaded", e), window.tt.miniProgram
    }, function (e) {
      if (p) {
        window.QaJSBridge && window.QaJSBridge.invoke ? setTimeout(e, 0) : document.addEventListener("QaJSBridgeReady", e);
        var n = window.qa;
        return {
          navigateTo: n.navigateTo,
          navigateBack: n.navigateBack,
          switchTab: n.switchTab,
          reLaunch: n.reLaunch,
          redirectTo: n.redirectTo,
          postMessage: n.postMessage,
          getEnv: n.getEnv
        }
      }
    }, function (e) {
      return document.addEventListener("DOMContentLoaded", e), o
    }], m = 0; m < f.length && !(l = f[m](_)); m++);
  l || (l = {});
  var E = "undefined" != typeof webUni ? webUni : {};
  if (!E.navigateTo)
    for (var b in l) t(l, b) && (E[b] = l[b]);
  return E.webView = l, E
}));
  • 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
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175

②在main.js上引入和搭桥

import * as uni from './api/web/web.js'  
document.addEventListener("UniAppJSBridgeReady", function() { 
	console.log("h5通信")
  uni.webView.postMessage({  
    data: {  
      action: "onReady",  
    },  
  }); 
    Vue.prototype.myUni = uni  //这样全局就能使用了
});
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

③H5页面如何给uni-app发消息?

例如点击某个按键,要求uni-app切换界面:
我们就可以在methods里加上这个按键的函数

methods:{
	back(){
		//返回
		this.myUni.webView.postMessage({  
			data: {  
				action: "back",  
			},  
		}); 
 },
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

在uni-app端的message监听函数里,加上‘back’这个字段的监听:

 methods: {
	   sendMsgToWebview() {
	        let _funName='msgFromUniapp'
	        let _data = {
	            msg:'refresh'
	          }
	        let currentWebview = this.$scope.$getAppWebview().children()[0];
	        currentWebview.evalJS(`${_funName}(${JSON.stringify(_data)})`)
		},
    message(event){
		// #ifdef APP-PLUS
		if(event.detail.data[0].action=='back'){
			console.log('关闭当前页面')
			uni.reLaunch({
				url:'/pages/mainPage/mainPage'//这里改成你自己项目的页面,可以不用reLaunch,这是我的需求才用reLaunch
			})
		}
		// #endif  

    }
  }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

其次,也要注意看看web-view组件有没有加上message的监听
在这里插入图片描述

3.uni-app加载web-view内嵌H5好慢?

由于uni-app加载web-view内嵌H5会有几秒是白屏的,加载也有点慢,所以我们可以在加载完H5的之前加个提示框,然后加载完之后把提示框关掉。
但是问题来了,假如这个提示框是我们自定义的,就没法完美显示,因为有web-view组件的页面,那个页面是被web-view全部占有了,就算动态分配高度这些给web-view组件,提示框也无法居中,会被web-view遮住,所以只能够用别的骚操作来实现提示框了。
不过一般的需求也不需要用自定义的提示框,所以我这里只分享普通的方式就好了。
可以在uni-app的onLoad里使用
uni.showLoading({ title:'加载中...' })
这个提示框的层级会比web-view的高。
然后在H5的main.js里
在这里插入图片描述
给uni-app传递一个信号,说明H5已经加载好了,uni-app收到这个信号的时候就把提示框关掉就好了

 message(event){
		// #ifdef APP-PLUS
		if(event.detail.data[0].action=='onReady'){
			uni.hideLoading()
		}
		// #endif  
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

目前遇到的一些坑就是这些了,还有一些别的功能和方法一般应该没啥问题,就不贴出来了。

补充一点:本来h5加上一些echarts的图表渲染之后,加载就更慢了,但是后来通过webpack,把加载web-view的时间从5秒缩短到了2秒!真不错!哈哈哈哈哈

加油吧,未来仍需努力!!!

声明:本文内容由网友自发贡献,转载请注明出处:【wpsshop】
推荐阅读
相关标签
  

闽ICP备14008679号