|
|
@@ -1,5 +1,5 @@
|
|
|
<script setup>
|
|
|
-import { computed } from "vue";
|
|
|
+import { onBeforeUnmount, onMounted } from "vue";
|
|
|
import { useStore } from "vuex";
|
|
|
import { useRoute } from "vue-router";
|
|
|
import MobileTabBar from "@/views/mobile/components/MobileTabBar.vue";
|
|
|
@@ -8,6 +8,82 @@ const route = useRoute();
|
|
|
const store = useStore();
|
|
|
|
|
|
// const cachedViews = computed(() => store.getters.cachedViews);
|
|
|
+
|
|
|
+let touchStartX = 0;
|
|
|
+let touchStartY = 0;
|
|
|
+
|
|
|
+const getScrollableParent = (target) => {
|
|
|
+ let element = target instanceof Element ? target : target?.parentElement;
|
|
|
+
|
|
|
+ while (element && element !== document.body) {
|
|
|
+ const style = window.getComputedStyle(element);
|
|
|
+ const canScrollY =
|
|
|
+ /(auto|scroll)/.test(style.overflowY) &&
|
|
|
+ element.scrollHeight > element.clientHeight;
|
|
|
+
|
|
|
+ if (canScrollY) {
|
|
|
+ return element;
|
|
|
+ }
|
|
|
+
|
|
|
+ element = element.parentElement;
|
|
|
+ }
|
|
|
+
|
|
|
+ return document.querySelector(".app-main-m");
|
|
|
+};
|
|
|
+
|
|
|
+const handleTouchStart = (event) => {
|
|
|
+ const touch = event.touches?.[0];
|
|
|
+ if (!touch) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ touchStartX = touch.clientX;
|
|
|
+ touchStartY = touch.clientY;
|
|
|
+};
|
|
|
+
|
|
|
+const handleTouchMove = (event) => {
|
|
|
+ if (event.touches.length !== 1) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ const touch = event.touches[0];
|
|
|
+ const deltaX = touch.clientX - touchStartX;
|
|
|
+ const deltaY = touch.clientY - touchStartY;
|
|
|
+
|
|
|
+ if (Math.abs(deltaX) > Math.abs(deltaY)) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ const scrollable = getScrollableParent(event.target);
|
|
|
+
|
|
|
+ if (!scrollable) {
|
|
|
+ event.preventDefault();
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ const scrollTop = scrollable.scrollTop;
|
|
|
+ const maxScrollTop = scrollable.scrollHeight - scrollable.clientHeight;
|
|
|
+ const isAtTop = scrollTop <= 0;
|
|
|
+ const isAtBottom = scrollTop >= maxScrollTop - 1;
|
|
|
+
|
|
|
+ if ((isAtTop && deltaY > 0) || (isAtBottom && deltaY < 0)) {
|
|
|
+ event.preventDefault();
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+onMounted(() => {
|
|
|
+ document.documentElement.classList.add("mobile-no-bounce");
|
|
|
+ document.body.classList.add("mobile-no-bounce");
|
|
|
+ document.addEventListener("touchstart", handleTouchStart, { passive: true });
|
|
|
+ document.addEventListener("touchmove", handleTouchMove, { passive: false });
|
|
|
+});
|
|
|
+
|
|
|
+onBeforeUnmount(() => {
|
|
|
+ document.documentElement.classList.remove("mobile-no-bounce");
|
|
|
+ document.body.classList.remove("mobile-no-bounce");
|
|
|
+ document.removeEventListener("touchstart", handleTouchStart);
|
|
|
+ document.removeEventListener("touchmove", handleTouchMove);
|
|
|
+});
|
|
|
</script>
|
|
|
|
|
|
<template>
|
|
|
@@ -29,8 +105,10 @@ const store = useStore();
|
|
|
<style scoped>
|
|
|
.app-shell {
|
|
|
width: 100%;
|
|
|
- min-height: 100vh;
|
|
|
+ height: 100%;
|
|
|
overflow-x: hidden;
|
|
|
+ overflow-y: hidden;
|
|
|
+ overscroll-behavior: none;
|
|
|
background: url("@/assets/mobile/images/bg.png") no-repeat;
|
|
|
background-position: center center;
|
|
|
background-size: cover;
|
|
|
@@ -38,7 +116,11 @@ const store = useStore();
|
|
|
|
|
|
.app-main-m {
|
|
|
width: 100%;
|
|
|
+ height: 100%;
|
|
|
overflow-x: hidden;
|
|
|
+ overflow-y: auto;
|
|
|
+ overscroll-behavior: contain;
|
|
|
+ -webkit-overflow-scrolling: touch;
|
|
|
z-index: 10;
|
|
|
position: relative;
|
|
|
}
|