aslan-h5/src/components/MaskLayer.vue

128 lines
2.8 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div v-show="maskLayerShow" class="mask-layer" @touchmove.prevent @wheel.prevent>
<div class="mask-layer__content" @touchmove.stop>
<slot></slot>
</div>
</div>
</template>
<script setup>
import { onUnmounted, watch } from 'vue'
const props = defineProps({
maskLayerShow: {
type: Boolean,
required: true,
},
})
let lockCount = 0
let lockedScrollY = 0
let previousBodyStyle = {}
let previousHtmlStyle = {}
const getStyleSnapshot = (el) => ({
overflow: el.style.overflow,
position: el.style.position,
top: el.style.top,
left: el.style.left,
right: el.style.right,
width: el.style.width,
touchAction: el.style.touchAction,
overscrollBehavior: el.style.overscrollBehavior,
})
const restoreStyleSnapshot = (el, style) => {
Object.keys(style).forEach((key) => {
el.style[key] = style[key]
})
}
// 弹窗展示时锁住背景页滚动iOS 需要固定 body 并在关闭后恢复滚动位置。
const lockPageScroll = () => {
if (typeof window === 'undefined' || typeof document === 'undefined') return
if (lockCount === 0) {
const body = document.body
const html = document.documentElement
lockedScrollY = window.scrollY || html.scrollTop || body.scrollTop || 0
previousBodyStyle = getStyleSnapshot(body)
previousHtmlStyle = getStyleSnapshot(html)
html.style.overflow = 'hidden'
html.style.touchAction = 'none'
html.style.overscrollBehavior = 'none'
body.style.overflow = 'hidden'
body.style.position = 'fixed'
body.style.top = `-${lockedScrollY}px`
body.style.left = '0'
body.style.right = '0'
body.style.width = '100%'
body.style.touchAction = 'none'
body.style.overscrollBehavior = 'none'
}
lockCount += 1
}
const unlockPageScroll = () => {
if (typeof window === 'undefined' || typeof document === 'undefined') return
if (lockCount <= 0) return
lockCount -= 1
if (lockCount === 0) {
restoreStyleSnapshot(document.body, previousBodyStyle)
restoreStyleSnapshot(document.documentElement, previousHtmlStyle)
window.scrollTo(0, lockedScrollY)
}
}
watch(
() => props.maskLayerShow,
(newVal) => {
if (newVal) {
lockPageScroll()
} else {
unlockPageScroll()
}
},
{ immediate: true }
)
onUnmounted(() => {
if (props.maskLayerShow) {
unlockPageScroll()
}
})
</script>
<style lang="scss" scoped>
* {
color: black;
}
.mask-layer {
width: 100vw;
height: 100vh;
background-color: #00000080;
position: fixed;
inset: 0;
z-index: 10000;
overflow: hidden;
touch-action: none;
overscroll-behavior: none;
-webkit-tap-highlight-color: transparent;
}
.mask-layer__content {
position: absolute;
inset: 0;
overflow-y: auto;
-webkit-overflow-scrolling: touch;
overscroll-behavior: contain;
}
</style>