uni-app仿生导航操作WebView(网页)
页面中的WebView嵌入一个网络页面后,顶部原生导航栏默认是整个页面返回,而实际上我们需要操作的是WebView内网页的后退,因此我们可以通过获取子WebView对象进行操作
需求描述
uni-app 的开发实际上本身就是在 WebView 上开发,只不过很多时候加载的是本地的网页资源。
而在 uni-app 中嵌入一个网络页面(外部资源),官方也提供了案例就是 vue 页面中在创建一个 web-view 标签。
<template>
<view>
<web-view src="http://www.mebugs.com/"></web-view>
</view>
</template>
加载一个网络页面需要解决一个比较尴尬的问题就是网页中做的导航和原生导航共存的问题。
对于 APP 而言,我们希望尽量使用原生导航,所以在实现中往往隐藏网页自带的导航,然后通过原生导航操作页面。
于是会发现一个问题,原生导航的返回往往是返回到上一个页面(这里指的是 uni-app 工程里面的上一页)。
解决方案
无限 WebView
- 创建一个公共的网络页面加载器(加载器就一个 web-view 组件,src 属性需由外部传入)
- 网络页面识别访问者是 APP 时,触发新页面访问需要向父组件发送消息(消息内容为新 URL),并阻断原生事件
- uni-app(加载器)监听消息,再次向加载器发起新的 navigate 跳转请求,携带新的消息中 URL
- 触发跳转后的原生导航就是常规的返回
优点:
- 几乎与原生完全一致的体验
- 前进后退的路由栈完全一致不会出错
缺点:
- 需要远端页面修改代码配合
- 性能不好(疯狂开 WebView 性能当然不好)
- 某些场景会不兼容,无限 WebView 类似于在浏览器上不断打开新 Tab 页,某些需要记录上一页或来源 reffer 的场景无法兼容
获取 webView 对象处理
- 网络页面加载器(加载器就一个 web-view 组件,src 属性可由外部传入)
- 获取当前页面的子 WebView(实际加载网络页面的 WebView)对象
- 监听子 WebView 对象并创建计数器
- 子 WebView 对象加载新页面是更新计数器
- 触发原生返回按钮时根据计数器判断执行子 WebView 回退还是页面 navigateBack
<template>
<view>
<web-view src="http://www.mebugs.com/"></web-view>
</view>
</template>
<script>
export default {
onNavigationBarButtonTap(e) {
var index = e.index;
if (index == 0) {
// 如果计数器>1 执行自WebView回退
if (this.index > 1) {
this.back();
} else {
// 框架回退
uni.navigateBack();
}
}
// 个人中心
if (index == 1)
uni.navigateTo({
url: "/pages/index/mine",
});
},
data() {
return {
currentWebview: false,
view: false,
index: 0,
};
},
onReady() {
this.initWebview();
},
methods: {
initWebview() {
//初始化并获取子WebView
// #ifdef APP-PLUS
this.currentWebview = this.$scope.$getAppWebview();
let this_ = this;
// 避免初始化失败 延时判断
setTimeout(function () {
this_.view = this_.currentWebview.children()[0];
if (this_.view) {
// 子WebView绑定打开新页面触发的事件方法
this_.view.onloading = this_.loadNewUrl();
} else {
// 如果子WebView还是没有 递归获取
this_.initWebview();
}
}, 1000);
// #endif
},
back() {
// 子webView回退
this.view.back();
this.index = this.index - 1;
},
loadNewUrl() {
// 计数器增加
this.index = this.index + 1;
},
},
};
</script>
