高扩展弹出层组件设计实现
作者:互联网
背景
随着业务的发展,弹窗逐渐替代翻页,承载越来越多的用户需求。由于没有统一、好用的公共弹窗组件,业务同学通常会编写属于自己的弹窗,这造成了一些问题:
- 用户体验不一致
- 大量重复代码,不易维护和升级
- 弹窗滚动穿透
- 未设置 iPhone 手机底部安全区域
我们急切的需要提供一个公共的弹窗组件,不仅要解决以上问题,还必须满足各种业务需求。
设计分析
分析过往的 UI,最常用的弹窗有下面两种:
由此可以得出如下结论:
- 组成:弹窗由蒙层和容器组成
- 位置:容器集中在底部和中间位置,可扩展为:上、右、下、左、中五个位置
- 容器内容:标题区、内容区、底部区组成
- 标题:可选,允许显示关闭按钮
- 内容:自定义,允许滚动
- 底部:可选
设计实现
解决滚动穿透问题
打开弹窗,给body设置类名hl-overflow-hidden
,关闭弹窗则移除。
document.body.classList.add('hl-overflow-hidden');
document.body.classList.remove('hl-overflow-hidden');
.hl-overflow-hidden {
overflow: hidden!important;
}
解决蒙层滚动穿透,核心在于设置touchmove
<div @touchmove="preventDefault"></div>
function preventDefault(event) {
if (typeof event.cancelable !== 'boolean' || event.cancelable) {
event.preventDefault();
}
event.stopPropagation()
}
高度自定义容器设计
将容器从上到下分为三个部分:head/body/foot。
head 区既可以便捷设置title,也可完全自定义。
body 区设置为默认插槽,根据内容高度自动设置滚动,并emit滚动事件。
foot 区由用户自定义,默认不展示。
<div class="huoli-popup fx-col" :style="{ height }">
<div class="huoli-popup-hd">
<template v-if="title">{{title}}</template>
<slot v-else name="title"></slot>
<img v-if="closable"
src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgBAMAAACBVGfHAAAAElBMVEVHcEw0N0o0OEouLkY0N0kwMFAuyLj8AAAABnRSTlMAT4ALcBBngfhBAAAAZUlEQVQoz2NgoA4wgDGYIRSrI0xAJABMmSgJQPiMSs5QWhEiIASTgTLgEjAWXAGUiVAAZSMpAHOQFYCVoCgAKUFRAFKCqgBTAF0LhqHo1mI4DN3pGJ5D9z5GAGEEIUYgY0QDxQAAIDoMW2GxKeQAAAAASUVORK5CYII="
@click="onClickClose" />
</div>
<div class="huoli-popup-bd" @scroll="onScroll">
<slot></slot>
</div>
<div class="huoli-popup-foot"><slot name="foot"></slot></div>
</div>
无依赖简单实现
结合 vant 使用
<template>
<Popup
v-model="show"
position="bottom"
round
:style="{ height, overflow: 'hidden' }"
get-container="body"
@close="onClickClose"
>
<div class="huoli-popup fx-col">
<div class="huoli-popup-hd">
<slot v-else name="title"></slot>
<img v-if="closable" src="./img/close@2x.png" class="huoli-popup-close-icon" @click="onClickClose" />
</div>
<div class="huoli-popup-bd" @scroll="onScroll">
<slot></slot>
</div>
<div class="huoli-popup-foot"><slot name="foot"></slot></div>
</div>
</Popup>
</template>
<script>
import { Popup } from "huoli-ui"
export default {
name: 'huoli-popup',
props: {
show: {
type: Boolean,
default: false,
},
closable: {
type: Boolean,
default: false,
},
height: {
type: String,
default: ',
},
},
components: {
Popup
},
methods: {
onClickClose() {
this.$emit('hide');
},
onScroll: throttle(function(e) {
this.$emit('scroll', e)
})
}
}
function throttle(func, wait = 50, immediate) {
let timeout
return function() {
const context = this;
const args = arguments;
if (immediate) {
func.apply(context, args);
immediate = false
}
if (timeout) return
timeout = setTimeout(function() {
timeout = null;
func.apply(context, args)
}, wait);
}
}
</script>
<style lang="scss">
.huoli-popup {
height: 100%;
.huoli-popup-hd {
min-height: 48px;
width: 100%;
background: inherit;
z-index: 1;
display: flex;
align-items: center;
justify-content: center;
font-size: 16px;
font-weight: 400;
color: #262626;
line-height: 20px;
}
.huoli-popup-close-icon {
position: absolute;
width: 16px;
height: 16px;
right: 16px;
top: 16px;
}
.huoli-popup-bd {
flex: 1;
box-sizing: border-box;
overflow-y: auto;
}
}
</style>
标签:body,扩展,event,huoli,弹出,组件,overflow,hidden,弹窗 来源: https://www.cnblogs.com/fayin/p/16465973.html