vue弹窗屏蔽滑动的两种解决方案

  在开发过程中,我们经常会遇到要加弹窗的需求,而如果当前页的展示数据一屏展示不完,则在打开弹窗后,有滑动操作时,页面也会随之滑动。那么如何处理这一问题呢?

常见问题

  我们开发过程中,最常见的问题上文已叙述:打开弹窗后,有滑动操作时,页面也会随之滑动。问题示意图如下:
背景数据仍可滑动

最终效果

我们来看一波正确示范
可滑动弹窗


解决方案

  两种解决方案,针对两种不同情况:

  1. 弹框数据少,无需滑动
  2. 弹框内数据需要滑动展示

1. 无需滑动弹窗

a. 思路

思路:
vue自带修饰符可解决该问题—— @touchmove.prevent

此方案重点在将@touchmove.prevent绑定到弹窗模块,然后动态控制弹窗显示隐藏即可。

b. 效果

不可滑动弹窗

c. 代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
<template>
<div class="modalTest">
<!-- 按钮组 -->
<div class="btn">
<el-button type="success" size="small" @click="modalSign1 = true">弹窗1</el-button>
</div>

<!-- 背景数据 -->
<div class="listBG">
<ul>
<li v-for="item in 50">这是第{{item}}条背景数据</li>
</ul>
</div>


<!-- 弹框1 -->
<div class="modalBox" v-if="modalSign1" @touchmove.prevent @click.self="modalSign1 = false">
<div class="modal">
<ul>
<li v-for="item in 8">这是第{{item}}条数据</li>
</ul>
</div>
</div>
</div>
</template>

<script>
export default {
data() {
return {
modalSign1: false, // 弹窗是否打开
}
}
}
</script>

2. 弹框内数据需要滑动展示

a. 思路

  首先,我们使用正常的vue操作,比如刚才的修饰符/语法糖进行操作时,虽然可以屏蔽掉背景数据滑动,但是该事件同时会将弹框内的滑动也阻止掉,我们则无法完成该需求。如果这个不行,我们还有别的方法来完成需求吗?
  我考虑到一种方案,但是属于DOM操作,与vue的初衷可能不太符合。不过此方案也不矢为一种能够有效解决问题的办法。

思路:
利用cssposition: fixed以及top: x px来固定位置。步骤分解如下:

  1. 写一个样式放到公共css中备用;
  2. 点击按钮,控制弹窗显示隐藏;
  3. 两个方法,一个控制将步骤1写的css动态添加到body上,另外一个则控制移除该效果;
    • 添加方法:①获取当前页面距离顶部高度,保存到data中;②给body添加步骤1的css;③设置body的高度为刚才获取到的高度。
    • 移除方法: ①将刚才冬天给body添加的css移除;②当前滑动高度设置为data中存储的高度。
b. 效果

可滑动弹窗

c. 两个案例完整代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
<template>
<div class="modalTest">
<!-- 按钮组 -->
<div class="btn">
<el-button type="success" size="small" @click="modalSign1 = true">弹窗1</el-button>
<br>
<el-button type="danger" size="small" @click="openModal">弹窗2</el-button>
</div>

<!-- 背景数据 -->
<div class="listBG">
<ul>
<li v-for="item in 50">这是第{{item}}条背景数据</li>
</ul>
</div>


<!-- 弹框1 -->
<div class="modalBox" v-if="modalSign1" @touchmove.prevent @click.self="modalSign1 = false">
<div class="modal">
<ul>
<li v-for="item in 8">这是第{{item}}条数据</li>
</ul>
</div>
</div>
<!-- 弹框2 -->
<div class="modalBox" v-if="modalSign2" @click.self="closeModal">
<div class="modal">
<ul>
<li v-for="item in 20">这是第{{item}}条数据</li>
</ul>
</div>
</div>
</div>
</template>

<script>
export default {
data() {
return {
modalSign1: false, // 弹窗是否打开
modalSign2: false, // 弹窗是否打开
scrollTop: undefined, // 距离顶端的值
className: 'modalOpen', // 类名
}
},
methods: {
// 打开弹层 要做的事
afterOpen () {
this.scrollTop = document.scrollingElement.scrollTop;
document.body.classList.add(this.className);
document.body.style.top = `-${this.scrollTop}px`;
},
// 弹层关闭之前 要做的事
beforeClose () {
document.body.classList.remove(this.className);
document.scrollingElement.scrollTop = this.scrollTop;
},
// 打开弹窗
openModal () {
this.modalSign2 = true;
this.afterOpen();
},
// 关闭弹窗
closeModal () {
this.modalSign2 = false;
this.beforeClose();
}
},
mounted() {

}
}
</script>

<style type="text/scss" lang="scss" scoped>
.modalTest{
width: 100%;
min-height: 100vh;
overflow: scroll;
.btn{
padding: 10px;
position: fixed;
top: 0;
left: 0;
z-index: 10;
&>button{
margin: 10px 0;
}
}
.listBG{
text-align: center;
line-height: 50px;
}
.modalBox{
width: 100vw;
height: 100vh;
overflow: hidden;
position: fixed;
top: 0;
left: 0;
background: rgba(0,0,0,0.4);
z-index: 999;

.modal{
width: 220px;
height: 280px;
overflow: scroll;
background: #fff;
border-radius: 10px;
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
-moz-box-shadow:10px 10px 9px #332A0D;
-webkit-box-shadow:10px 10px 9px #332A0D;
box-shadow:10px 10px 9px #332A0D;
padding: 30px 0 0;

ul{
text-align: center;
li{
list-style: none;
line-height: 30px;
}
}
}
}
}
</style>
d. 备注

.modalOpen的css样式,放在公共样式中,因为我们要改变的是body的样式,因此在组件中写的样式可能会失效。例如,我将样式放在了src/assets/css/common.css

1
2
3
4
5
6
/*弹层*/
body.modalOpen {
-webkit-overflow-scrolling:touch;
position: fixed;
width: 100%;
}

---本文结束感谢您的阅读---

本文标题:vue弹窗屏蔽滑动的两种解决方案

文章作者:Lomo 朱幸民

发布时间:2019年05月28日 - 14:38:59

最后更新:2019年07月10日 - 08:45:48

原始链接:https://www.zhuxingmin.com/2019/05/28/vue弹窗屏蔽滑动的两种解决方案/

许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。

请作者喝杯咖啡吧~
0%