赞
踩
说起来话长,最近的项目需求里,有个图超级复杂,uni-app使用echarts之后在真机渲染不出来,但是在h5又可以渲染出来,而这个bug echarts开发者好像还没有修复。所以导致所在图表的一整个页面都只好用H5来实现了。
另外,使用这种方法还有另外一个优点,就是app的这个界面可以热更新,就不需要通过重新安装apk来进行更新了。
只不过,我遇到了很多的坑,后面会一一列出来的。
官网有虽然有教程,但我还是把自己代码铺出来,因为感觉有些地方新手可能会很迷惘。
这是官网的有关这个组件的地址:https://uniapp.dcloud.net.cn/component/web-view.html#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>
首先在uni-app端,在页面加载完之后,增加一个全局函数,这个函数的声明放在methods里就好
sendMsgToWebview() {
let _funName='msgFromUniapp'
let _data = {
msg:'refresh'
}
let currentWebview = this.$scope.$getAppWebview().children()[0];
currentWebview.evalJS(`${_funName}(${JSON.stringify(_data)})`)
},
然后可以在加载完dom之后的声明周期函数里使用,例如onReady
onReady() {
// #ifdef H5
window.addEventListener("message", this.message, false)
// #endif
this.sendMsgToWebview()
},
然后在h5端的mounted钩子函数里,加上
mounted() {
let that=this
window.msgFromUniapp = function(arg) {
//注意this指向
if(arg.msg=='refresh'){
console.log('shuaxin')
//当uni-app发送这个refresh的时候,h5可以在这里监听并做想要做的事
}
}
},
例如:
在uni-app的web-view上的url加上参数
url:'http://localhost:8080'+'/#/index?token='+ uni.getStorageSync("accessToken")+'&userId='+getApp().globalData.global_user.id
在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
当然,拿到的token也可以把它存到vuex,在这里我就不多说了。
我是新建了个目录和文件用来存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
}));
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 //这样全局就能使用了
});
例如点击某个按键,要求uni-app切换界面:
我们就可以在methods里加上这个按键的函数
methods:{
back(){
//返回
this.myUni.webView.postMessage({
data: {
action: "back",
},
});
},
}
在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
}
}
其次,也要注意看看web-view组件有没有加上message的监听
由于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
}
目前遇到的一些坑就是这些了,还有一些别的功能和方法一般应该没啥问题,就不贴出来了。
补充一点:本来h5加上一些echarts的图表渲染之后,加载就更慢了,但是后来通过webpack,把加载web-view的时间从5秒缩短到了2秒!真不错!哈哈哈哈哈
加油吧,未来仍需努力!!!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。