實際開發中,總免不了使用彈窗,如果彈窗比較短,內容不需要滑動,那還好處理,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 的這個組件來使用