实际开发中,总免不了使用弹窗,如果弹窗比较短,内容不需要滑动,那还好处理,vue中直接阻止滑动就可以了,但是如果弹窗内的内容需要滑动,那就有点麻烦了,之前看到的方案都是给body设置fixed,但是事实上都不是很好,还好,网上找了一种解决方案,实现思路比较简单直接,滑动的时候监听touch事件,通过target来判断滑动的是谁,如果是遮罩层,那么直接preventDefault(),当然,这还没完,还需要处理滑动的边界情况,在最顶部以及最底部,此时,如果继续滑动的话,底部的内容依然会滑动,所以,在边界情况下还是需要阻止滑动,下面以自己实现的mask组件为例来说明把,其实这基本就实现了需求
话不多说,下面附上自己写的一个通用组件
<template>
<div class="lo-mask" @touchstart="start" @touchmove="move" @touchend="end">
<div class="mask-container" ref="container">
<p v-for="val in 20">{{val}}</p>
<div class="content">
<slot name="title"></slot>
<slot name="content"></slot>
</div>
<footer>
<button v-if="cancel" @click="cancelBtn" class="btn cancel">{{cancel}}</button>
<span class="line" v-if="cancel&&confirm"></span>
<button v-if="confirm" @click="successBtn" class="btn">{{confirm}}</button>
</footer>
</div>
</div>
</template>
<script>
export default {
name: 'loMask',
props: {
cancel: {
type: String,
default: ''
},
confirm: {
type: String,
default: ''
}
},
data() {
return {
startY: 0
}
},
methods: {
successBtn() {},
cancelBtn() {},
start(e) {
// console.log(e.target);
// let target = e.target;
// console.log(target.className);
console.log(e);
this.startY = e.touches[0].clientY;
},
move(e) {
// console.log(e.target);
// e.preventDefault()
let container = this.$refs.container;
let target = e.target;
let sTop = container.scrollTop, // 滚动的高度 (滚动卷去的高度)
sHeight = container.scrollHeight, // 可滚动的高度 (实际总高度)
vHeight = container.offsetHeight; // 视窗的高度 (可视区域高度)
if (target.className === 'lo-mask') {
e.preventDefault()
}
let newY = e.touches[0].clientY;
let dis = newY - this.startY;
if (dis > 0) {
// 向下
if (sTop <= 0&& e.cancelable) { //是否是最上面
e.preventDefault()
}
} else {
// 向上
if (sTop + vHeight >= sHeight&& e.cancelable) { //是否滑动到底了
e.preventDefault()
}
}
},
end() {}
}
}
</script>
<style scoped lang="scss">
.lo-mask{
position: fixed;
width: 100%;
height: 100%;
background:rgba(0, 0, 0, 0.7);
z-index: 50;
top: 0;
left: 0;
display: flex;
align-items: center;
justify-content: center;
padding-left: 0.2rem;
padding-right: 0.2rem;
overflow: auto;
}
.mask-container{
position: relative;
display: flex;
flex-direction: column;
width: 2.7rem;
min-height: 1.5rem;
max-height: 2rem;
overflow-y: scroll;
background-color: #fff;
border-radius: 0.08rem;
box-shadow: 0 3px 19px rgba(89, 89, 89, 0.85);
}
.content{
flex: 1;
}
footer{
display: flex;
box-sizing: content-box;
align-items: center;
justify-content: space-around;
width: 100%;
height: 0.4rem;
background-color: #f7f7f7;
border-top: 1px solid #E2E2E2;
border-radius: 0 0 0.08rem 0.08rem;
.btn{
flex: 1;
height: 0.4rem;
color: #E9327B;
font-size: 0.17rem;
font-weight: bold;
}
.line{
width: 1px;
height: 0.4rem;
background-color: #E2E2E2;
}
}
</style>
直接复制过去就可以用,还是不错的
自己测试了下,效果还行,不过vant-ui里面的popup组件就可以实现上述效果,大家可以引用vant-ui 的这个组件来使用