江夏
主 题
前言
使用vant
开发的h5页面嵌入到webview
中,遇到的一些问题。
webview中动态设置导航栏高度
一般为了和手机上的状态栏适配, 一般需要动态设置导航栏的padding-top的
值。原生app
会提供一些原生方法给js调用,方便获取一些原生才有的属性和数据。js这边一般封装一个bridge.js获取到原生的方法。
用到 window.WebViewJavascriptBridge
对象,WebViewJavascriptBridgeReady
事件。
JavaScript
// bridge.js
const isAndroid = navigator.userAgent.indexOf('Android') > -1 || navigator.userAgent.indexOf('Adr') > -1
const isiOS = !!navigator.userAgent.match(/(i[^;]+;( U;)? CPU.+Mac OS X/)
// 这是必须要写的,用来创建一些设置
function setupWebViewJavascriptBridge (callback) {
// Android使用
if (isAndroid) {
if (window.WebViewJavascriptBridge) {
callback(window.WebViewJavascriptBridge)
} else {
document.addEventListener(
'WebViewJavascriptBridgeReady',
() => {
callback(window.WebViewJavascriptBridge)
},
false
)
}
sessionStorage.phoneType = 'android'
}
// iOS使用
if (isiOS) {
if (window.WebViewJavascriptBridge) {
return callback(window.WebViewJavascriptBridge)
}
if (window.WVJBCallbacks) {
return window.WVJBCallbacks.push(callback)
}
window.WVJBCallbacks = [callback]
var WVJBIframe = document.createElement('iframe')
WVJBIframe.style.display = 'none'
WVJBIframe.src = 'wvjbscheme://__BRIDGE_LOADED__'
document.documentElement.appendChild(WVJBIframe)
setTimeout(() => {
document.documentElement.removeChild(WVJBIframe)
}, 0)
sessionStorage.phoneType = 'ios'
}
}
// 注册回调函数,第一次连接时调用 初始化函数(android需要初始化,ios不用)
setupWebViewJavascriptBridge((bridge) => {
if (isAndroid) {
// 初始化
bridge.init((message, responseCallback) => {
var data = {
'Javascript Responds': 'Wee!'
}
responseCallback(data)
})
}
})
export default {
// js调APP方法 (参数分别为:app提供的方法名 传给app的数据 回调)
callHandler (name, data, callback) {
setupWebViewJavascriptBridge((bridge) => {
bridge.callHandler(name, data, callback)
})
},
// APP调js方法 (参数分别为:js提供的方法名 回调)
registerHandler (name, callback) {
setupWebViewJavascriptBridge((bridge) => {
bridge.registerHandler(name, (data, responseCallback) => {
callback(data, responseCallback)
})
})
},
isAndroid,
isiOS
}
使用封装
JavaScript
// js 调 APP
function callApp (params, callback) {
let data = {}
for (const key in params) {
data = {
funname: key,
value: params[key]
}
}
this.$bridge.callHandler('callFunction', data, (res) => {
console.log(res)
if (res) {
res = JSON.parse(res)
res.code = Number(res.code)
if (res.code === -10000) {
this.$zcToast.msg('APP版本过低,请升级后再使用')
} else if (res.code !== 0) {
this.configTimer && clearTimeout(this.configTimer)
this.configTimer = setTimeout(() => {
res.msg && this.$zcToast.msg(res.msg)
}, 500)
}
// if (res.code !== 0) {
// this.configTimer && clearTimeout(this.configTimer)
// this.configTimer = setTimeout(() => {
// res.msg && this.$zcToast.msg(res.msg)
// }, 500)
// }
}
callback && callback(res)
// console.log('获取app响应数据:' + JSON.stringify(res))
})
}
// APP 调 js
function appCall (callback) {
this.$bridge.registerHandler('appCallJS', (res, responseCallback) => {
// console.log('APP 调 js showStationList', res)
res = res && JSON.parse(res)
if (res && +res.value.code === 0) {
switch (res.funname) {
case 'token_mobile':
window.sessionStorage.setItem('token', res.value.data.token)
break
case 'userInfo_mobile':
window.sessionStorage.setItem('user', JSON.stringify(res.value.data))
Vue.prototype.$user = res.value.data
break
}
}
callback && callback(res)
})
}
封装导航栏
JavaScript
<template>
<van-nav-bar
left-arrow
:border="border"
:title="title"
:fixed="fixed"
:z-index="99"
@click-left="clickLeft"
:style="{paddingTop:(fixed&&statusBarHeight)+'px'}"
/>
</template>
<script>
import { NavBar } from 'vant'
export default {
name: 'NavBar',
components: {
[NavBar.name]: NavBar
},
props: {
fixed: {
type: Boolean,
default: true
},
border: {
type: Boolean,
default: true
},
// 默认返回原生app no/yes
backApp: {
type: String,
default: 'yes'
},
bgColor: {
type: String,
default: ''
},
title: {
type: String,
default: ''
},
// 自定义返回
customBack: {
type: Function,
default: undefined
}
},
data () {
return {
value: 'new template',
statusBarHeight: 0
}
},
created () {
// 状态栏高度
this.callApp({
statusBarHeight_mobile: ''
}, (res) => {
if (res.code === 0) {
console.log(res.data.dpptHeight)
this.statusBarHeight = res.data.dpptHeight || 44// res.data.height || 44
}
})
},
methods: {
clickLeft () {
if (this.customBack) {
this.customBack()
} else {
// 不根据vue路由返回的话,就返回原生app
if (this.backApp === 'no') {
this.$router.go(-1)
} else {
// 调用app方法返回app页面
this.callApp({ back_mobile: '' })
}
}
}
}
}
</script>
<style lang="less" scoped>
</style>
全部评论(0)