这是我目前用的办法,每隔50毫秒尝试获取一次,重试20次还获取不到则报错。一般情况下200毫秒内可以获取成功
<template>
<web-view :src="s.url" @message="s.onPostMessage"></web-view>
</template>
<script setup lang="ts">
import {tryGet} from '../../util/tryGet'
import {showModal} from '../../util/modal'
import {handleMessage} from '../../util/postMessage'
import {react} from '../../util/react'
import {onBackPress, onLoad, onReady} from '@dcloudio/uni-app'
import {getCurrentInstance} from 'vue'
const s = react(() => new class {
appWebview: any = null
canBack = false
url = ''
onPostMessage(e: any) {
console.debug('receive post message:', e)
const m = e.detail.data[0] || {}
handleMessage(m)
}
getAppWebview() {
if (s.appWebview) return s.appWebview
else if (s.appWebview === undefined) showModal('错误', 'webview初始化失败,请退出重试')
else uni.showToast({
title: '加载中,请稍候',
icon: 'loading'
})
}
}())
const { proxy } = getCurrentInstance()!
console.debug('proxy: %o', proxy)
onReady(async () => {
// #ifdef APP-PLUS
const parent = proxy!.$parent! as any // todo use getCurrentPages() instead?
s.appWebview = await tryGet(() => parent.$getAppWebview().children()[0], 50, 20)
const wv = s.getAppWebview()
if (!wv) return
//允许双指缩放
wv.setStyle({
scalable: true
})
//每当webview地址发生变化,更新是否允许后退的flag
wv.addEventListener('loaded', () => wv.canBack((e: any) => s.canBack = e.canBack))
//todo 拦截a标签文件下载(如果不拦截使用原生的链接跳转,页面会显示错误,且无下载进度,也不能直接安装下载后的安装包)
// #endif
})
onLoad(params => {
const url = decodeURIComponent(params.url || '')
console.debug('webview onLoad. url: ', url)
s.url = url
})
onBackPress((e: any) => {
// #ifdef APP-PLUS
if (e.from === 'navigateBack') return false //使用了uni api发起后退事件,不在此处处理
//否则,用户按下了物理后退键
if (s.canBack) { //webview可后退(history页面数大于1),则使用webview api进行后退
s.getAppWebview().back()
return true
} //否则,webview已没有更多页面可供后退,让框架调用默认的物理后退键功能(提示重复按键退出app)
// #endif
return false
})
</script>
tryGet:
import {delay} from './delay'
export async function tryGet<T>(getter: () => T, interval: number, maxTimes: number) {
for (let i = 0; i < maxTimes; i++) {
await delay(interval)
const r = await getter()
if (r) return r
}
return undefined
}
delay:
export async function delay(ms: number) {
return new Promise(resolve => setTimeout(resolve, ms))
}
react:
import {reactive} from 'vue'
export function react<T extends object>(block: () => T) {
return reactive(block())
}
2 个回复
水车
楼主,解决了吗?我也遇到了同样的问题
4***@qq.com (作者)
这是我目前用的办法,每隔50毫秒尝试获取一次,重试20次还获取不到则报错。一般情况下200毫秒内可以获取成功
tryGet:
delay:
react: