App使用webview套壳引入h5(三)——解决打包为app后在安卓机可物理返回但是在苹果手机无法测滑返回的问题

news2025/6/8 0:37:53

话不多说,直接放最终版本代码。

解决思路是:如果设备是ios设备在myH5中监听 touchstart 和touchend事件

经过 App使用webview套壳引入h5的最终代码如下
myApp中,entry.vue代码如下:

<template>
	<view class="entry-page" :style="{ paddingTop: safeAreaInsets.top + 'px' }">
		<web-view :webview-styles="webviewStyles" :src="webviewUrl" @message="getH5Message" ref="webViewRef"></web-view>
	</view>
</template>

<script>
export default {
	data() {
		return {
			statusBarHeight: 100,
			safeAreaInsets: {},
			webviewUrl: 'myLink', 
			hasBottomSafeArea: false,
			webviewStyles: {
				progress: {
					color: '#007aff',
					top: 0
				},
				// iOS侧滑返回配置
				ios: {
					allowsBackForwardNavigationGestures: true, // 启用WKWebView侧滑手势
					bounces: false // 禁用弹性效果
				}
			},
			webview: '',
			isIOS: false,          // 判断是否为iOS设备
			webviewCanBack: false  // WebView是否可返回
		};
	},
	onReady() {
		var currentWebview = this.$scope.$getAppWebview().children()[0];
		this.webview = currentWebview; // 缓存WebView实例
		
		currentWebview.addEventListener('loaded', () => {			currentWebview.evalJS('$("ul.fed-part-rows a[href*=\'resource.i847.cn\']").parent().hide();');

		});
	},
	onLoad(options) {
		// #ifdef APP-PLUS
		this.isIOS = uni.getSystemInfoSync().platform === 'ios'; // 检测iOS设备
		
		let _this = this;
		let height = 0;
		let statusbar = 0;
		const sysInfo = uni.getSystemInfoSync();
		this.safeAreaInsets = sysInfo.safeAreaInsets;
		console.log('top--------', sysInfo);
		this.statusBarHeight = sysInfo.statusBarHeight;
		height = sysInfo.windowHeight;
		let currentWebview = this.$scope.$getAppWebview();
		
		setTimeout(() => {
			var wv = currentWebview.children()[0];
			console.log('top--------222222222', _this.statusBarHeight);
			wv.setStyle({
				top: _this.statusBarHeight,
				height: height - _this.statusBarHeight,
				scalable: false
			});

		}, 200);
		// #endif
	},
	onBackPress(e) {
		// 响应返回事件(关键修改,此处测试发行仅在打包为安卓的情况下可响应onBackPress)
		if (this.isIOS) {
			// iOS设备:优先WebView内部返回
			if (this.webviewCanBack) {
				this.webview.back(); // WebView返回上一级H5页面
				return true; // 拦截默认返回
			}
		}
		
		// 其他情况执行原有逻辑
		this.webView = this.$mp.page.$getAppWebview().children()[0];
		this.webView.evalJS('window.getPageUrl()');
		return true;
	},
	methods: {
		test() {
			console.log('test webview');
		},
		dealBackEvent() {
			console.log('dealBackEvent webview');
		},
		showCurrentPage(pageInfo) {
			console.log('showCurrentPage', pageInfo);
			if (pageInfo.pathname) {
				const targetArray = ['pages/index/index', 'tab页2', 'tab页3'];
				const processedString = pageInfo.pathname.replace('myLink地址中的页面公共路径', '');
				const exists = targetArray.includes(processedString);

				if (exists) {
					console.log('showCurrentPage ----------1');
					uni.showModal({
						title: '提示',
						content: '确定要退出吗?',
						success: (res) => {
							if (res.confirm) {
								plus.runtime.quit();
							}
						}
					});
				} else {
					console.log('showCurrentPage ----------2');
					// 优先WebView返回(关键修改)
					if (this.webviewCanBack) {
						this.webview.back();
					} else {
						this.webView.back();
					}
				}
			}
		},
		getH5Message(e) {
			console.log('来自webview的消息*******************', e);
			var item = e.detail.data[0];
			switch (item.type) {
				case 'back':
					this.operation();
					break;
				case 'outApp':
					this.back();
					break;
				case 'isFun':
					this[item.action](item.message);
					break;
				case 'historyChange':
					// 接收H5历史变化通知(关键修改)
					this.webviewCanBack = item.data.canBack;
					break;
				case 'iosBack':
					// 接收iOS返回通知(关键修改)
					if (!item.data.canBack) {
						uni.navigateBack();
					}
					break;
				default:
					uni.showToast({
						title: item.message,
						duration: 2000
					});
					break;
			}
		},
		operation() {
			// #ifdef APP-PLUS
			this.webView = this.$mp.page.$getAppWebview().children()[0];
			console.log('operation********', this.webView);
			// #endif
		},
		back() {
			uni.showModal({
				title: '提示',
				content: '是否退出系统?',
				success: function (res) {
					if (res.confirm) {
						plus.runtime.quit();
					} else if (res.cancel) {
						console.log('用户点击取消');
					}
				}
			});
		}
	}
};
</script>

<style>
.entry-page {
	background-color: #f8f8f8;
}

.webview-container {
	flex: 1;
	width: 100%;
}
</style>

myH5项目中
记得引入webviewJs,参考 App使用webview套壳引入h5(一)
App.vue的代码如下

<script>
	export default {
		data() {
			return {
				isIos: false,
				transitionName: '', // 过渡动画的名称
				startPosition: {
					x: 0,
					y: 0
				}, // 手势开始时的位置
			};
		},
		created() {
			console.log("at app created---0", this.startPosition);
			// 初始化数据
			this.startPosition = {
				x: 0,
				y: 0
			};
			this.isIOS = uni.getSystemInfoSync().platform === 'ios'; // 检测iOS设备
			console.log("at app created---1", this.startPosition,this.isIOS);
		},
		mounted() {
			console.log("at app mounted---0", this.startPosition);
			let that = this
			// 使用$nextTick确保DOM和数据完全初始化后执行
			this.$nextTick(() => {
				console.log("at app mounted---1", that.startPosition);
				console.log("at app mounted---2", that.startPosition.x);

				// 初始化事件监听
				that.initEventListeners();
			});
		},
		methods: {
			// 将事件监听逻辑提取为单独的方法
			initEventListeners() {
				if (this.isIOS) {
					// 监听touchstart事件
					window.addEventListener('touchstart', (event) => {
						this.handleTouchStart(event);
					});

					// 监听touchend事件
					window.addEventListener('touchend', (event) => {
						this.handleTouchEnd(event);
					});
				}
				// 确保uni对象存在后执行初始化
				this.initUniAppBridge();

			},

			// 处理touchstart事件
			handleTouchStart(event) {
				this.startPosition.x = event.touches[0].pageX;
				this.startPosition.y = event.touches[0].pageY;
			},

			// 处理touchend事件
			handleTouchEnd(event) {
				const endPosition = {
					x: event.changedTouches[0].pageX,
					y: event.changedTouches[0].pageY,
				};

				// 计算手势滑动的距离
				const deltaX = endPosition.x - this.startPosition.x;
				const deltaY = endPosition.y - this.startPosition.y;
				console.log("touchend---------2");
				// 判断滑动方向与滑动距离是否符合返回操作的条件
				if (Math.abs(deltaX) > Math.abs(deltaY) && Math.abs(deltaX) > 30) {
					if (deltaX > 0) {
						// 获取当前路由栈的长度
						const pages = getCurrentPages();
						const stackLength = pages.length;
						console.log('[H5] popstate触发,历史长度:', window.history.length, this.$router, stackLength);
						// 向右滑动,执行返回上一页的操作
						this.transitionName = 'slide-right';
						// this.$router.go(-1);
						uni.navigateBack()
					}
					// else if (deltaX < 0) {
					//         // 向左滑动,执行前进一页的操作
					//         this.transitionName = 'slide-left';
					//         this.$router.go(1);
					//       }
				}
			},

			// 初始化与uni-app的桥接
			initUniAppBridge() {
				// 和webview进行网页通信
				document.addEventListener('UniAppJSBridgeReady', () => {
					uni.webView.getEnv((res) => {
						console.log('当前环境:' + JSON.stringify(res));
					});
					uni.webView.postMessage({
						data: {
							message: '我是来自H5的消息',
							action: 'test',
							type: 'isFun'
						}
					});
				});

				window.getPageUrl = (arg) => {
					uni.webView.postMessage({
						data: {
							action: 'showCurrentPage',
							message: location,
							type: 'isFun',
						}
					});
				};
			},
		},
		beforeDestroy() {
			if (this.isIos) {
				// 移除所有事件监听
				window.removeEventListener('touchstart', this.handleTouchStart);
				window.removeEventListener('touchend', this.handleTouchEnd);
			}
		}
	}
</script>

<style lang="scss">
</style>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2403529.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

2025年渗透测试面试题总结-ali 春招内推电话1面(题目+回答)

安全领域各种资源&#xff0c;学习文档&#xff0c;以及工具分享、前沿信息分享、POC、EXP分享。不定期分享各种好玩的项目及好用的工具&#xff0c;欢迎关注。 目录 ali 春招内推电话1面 一、Web安全核心理解 二、熟悉漏洞及防御方案 三、UDF提权原理与防御 四、XSS Fuzz…

Reactor和Proactor

reactor的重要组件包括&#xff1a;Event事件、Reactor反应堆、Demultiplex事件分发器、Eventhandler事件处理器。

黄晓明新剧《潜渊》定档 失忆三面间谍开启谍战新维度

据悉&#xff0c;黄晓明领衔主演的谍战剧《潜渊》已于近日正式定档6月9日&#xff0c;该剧以“失忆三面间谍”梁朔为核心&#xff0c;打破传统谍战剧的框架和固有角度&#xff0c;以一种特别的视角将悬疑感推向极致。剧中&#xff0c;梁朔因头部受伤失去记忆&#xff0c;陷入身…

物联网嵌入式开发实训室建设方案探讨(高职物联网应用技术专业实训室建设)

一、建设背景与目标 在当今数字化时代&#xff0c;物联网技术正以前所未有的速度改变着人们的生活和工作方式。从智能家居到工业自动化&#xff0c;从智能交通到环境监测&#xff0c;物联网的应用场景无处不在。根据市场研究机构的数据&#xff0c;全球物联网设备连接数量预计…

集成学习三种框架

集成学习通过组合多个弱学习器构建强学习器&#xff0c;常见框架包括Bagging&#xff08;装袋&#xff09;、Boosting&#xff08;提升&#xff09; 和Stacking&#xff08;堆叠&#xff09; 一、Bagging&#xff08;自助装袋法&#xff09; 核心思想 从原始数据中通过有放回…

在UI界面内修改了对象名,在#include “ui_mainwindow.h“没更新

​原因​&#xff1a;未重新编译UI文件​​ Qt的UI文件&#xff08;.ui&#xff09;需要通过​​uic工具&#xff08;Qt的UI编译器&#xff09;​​生成对应的ui_*.h头文件。如果你在Qt Designer中修改了对象名&#xff0c;但没有​​重新构建&#xff08;Rebuild&#xff09;…

Neovim - 常用插件,提升体验(三)

文章目录 nvim-treelualineindent-blanklinetelescopegrug-far nvim-tree 官方文档&#xff1a;https://github.com/nvim-tree/nvim-tree.lua 以前我们都是通过 :e 的方式打开一个 buffer&#xff0c;但是这种方式需要记忆文件路径&#xff0c;因此这里可以通过 nvim-tree 插…

SOC-ESP32S3部分:31-ESP-LCD控制器库

飞书文档https://x509p6c8to.feishu.cn/wiki/Syy3wsqHLiIiQJkC6PucEJ7Snib ESP 系列芯片可以支持市场上常见的 LCD&#xff08;如 SPI LCD、I2C LCD、并行 LCD (Intel 8080)、RGB/SRGB LCD、MIPI DSI LCD 等&#xff09;所需的各种时序。esp_lcd 控制器为上述各类 LCD 提供了一…

【云安全】以Aliyun为例聊云厂商服务常见利用手段

目录 OSS-bucket_policy_readable OSS-object_public_access OSS-bucket_object_traversal OSS-Special Bucket Policy OSS-unrestricted_file_upload OSS-object_acl_writable ECS-SSRF 云攻防场景下对云厂商服务的利用大同小异&#xff0c;下面以阿里云为例 其他如腾…

读文献先读图:GO弦图怎么看?

GO弦图&#xff08;Gene Ontology Chord Diagram&#xff09;是一种用于展示基因功能富集结果的可视化工具&#xff0c;通过弦状连接可以更直观的展示基因与GO term&#xff08;如生物过程、分子功能等&#xff09;之间的关联。 GO弦图解读 ①内圈连线表示基因和生物过程之间的…

怎么让大语言模型(LLMs)自动生成和优化提示词:APE

怎么让大语言模型(LLMs)自动生成和优化提示词:APE https://arxiv.org/pdf/2211.01910 1. 研究目标:让机器自己学会设计提示词 问题:大语言模型(如GPT-3)很强大,但需要精心设计的“提示词”才能发挥最佳效果。过去靠人工设计提示词,费时费力,还可能因表述差异导致模…

实现单例模式的常见方式

前言 java有多种设计模式&#xff0c;如下图所示&#xff1a; 单例模式它确保一个类只有一个实例&#xff0c;并提供一个全局访问点。 1、单例模式介绍 1.1、使用原因 为什么要使用单例模式&#xff1f; 1. 控制资源访问 核心价值&#xff1a;确保对共享资源&#xff08;如…

day20 leetcode-hot100-38(二叉树3)

226. 翻转二叉树 - 力扣&#xff08;LeetCode&#xff09; 1.广度遍历 思路 这题目很简单&#xff0c;就是交换每个节点的左右子树&#xff0c;也就是相当于遍历到某个节点&#xff0c;然后交换子节点即可。 具体步骤 &#xff08;1&#xff09;创建队列&#xff0c;使用广…

OpenVINO环境配置--OpenVINO安装

TOC环境配置–OpenVINO安装 本节内容 OpenVINO 支持的安装方式有很多种&#xff0c;每一种操作系统以及语言都有对应的安装方法&#xff0c;在官网上有很详细的教程&#xff1a;   我们可以根据自己的需要&#xff0c;来点选环境配置和安装方法&#xff0c;然后网页会给出正…

黑龙江云前沿服务器租用:便捷高效的灵活之选​

服务器租用&#xff0c;即企业直接从互联网数据中心&#xff08;IDC&#xff09;提供商处租赁服务器。企业只需按照所选的服务器配置和租赁期限&#xff0c;定期支付租金&#xff0c;即可使用服务器开展业务。​ 便捷快速部署&#xff1a;租用服务器能极大地缩短服务器搭建周期…

论文解读:Locating and Editing Factual Associations in GPT(ROME)

论文发表于人工智能顶会NeurIPS(原文链接)&#xff0c;研究了GPT(Generative Pre-trained Transformer)中事实关联的存储和回忆&#xff0c;发现这些关联与局部化、可直接编辑的计算相对应。因此&#xff1a; 1、开发了一种因果干预方法&#xff0c;用于识别对模型的事实预测起…

学习设计模式《十二》——命令模式

一、基础概念 命令模式的本质是【封装请求】命令模式的关键是把请求封装成为命令对象&#xff0c;然后就可以对这个命令对象进行一系列的处理&#xff08;如&#xff1a;参数化配置、可撤销操作、宏命令、队列请求、日志请求等&#xff09;。 命令模式的定义&#xff1a;将一个…

十三、【核心功能篇】测试计划管理:组织和编排测试用例

【核心功能篇】测试计划管理&#xff1a;组织和编排测试用例 前言准备工作第一部分&#xff1a;后端实现 (Django)1. 定义 TestPlan 模型2. 生成并应用数据库迁移3. 创建 TestPlanSerializer4. 创建 TestPlanViewSet5. 注册路由6. 注册到 Django Admin 第二部分&#xff1a;前端…

手撕 K-Means

1. K-means 的原理 K-means 是一种经典的无监督学习算法&#xff0c;用于将数据集划分为 kk 个簇&#xff08;cluster&#xff09;。其核心思想是通过迭代优化&#xff0c;将数据点分配到最近的簇中心&#xff0c;并更新簇中心&#xff0c;直到簇中心不再变化或达到最大迭代次…

SmolVLA: 让机器人更懂 “看听说做” 的轻量化解决方案

&#x1f9ed; TL;DR 今天&#xff0c;我们希望向大家介绍一个新的模型: SmolVLA&#xff0c;这是一个轻量级 (450M 参数) 的开源视觉 - 语言 - 动作 (VLA) 模型&#xff0c;专为机器人领域设计&#xff0c;并且可以在消费级硬件上运行。 SmolVLAhttps://hf.co/lerobot/smolvla…