You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
294 lines
5.7 KiB
294 lines
5.7 KiB
<template> |
|
<view v-if="showPopup" class="uni-popup" :class="[popupstyle]" @touchmove.stop.prevent="clear"> |
|
<uni-transition v-if="maskShow" :mode-class="['fade']" :styles="maskClass" :duration="duration" :show="showTrans" |
|
@click="onTap" /> |
|
<uni-transition :mode-class="ani" :styles="transClass" :duration="duration" :show="showTrans" @click="onTap"> |
|
<view class="uni-popup__wrapper-box" @click.stop="clear"> |
|
<slot /> |
|
</view> |
|
</uni-transition> |
|
</view> |
|
</template> |
|
|
|
<script> |
|
import uniTransition from '../uni-transition/uni-transition.vue' |
|
import popup from './popup.js' |
|
/** |
|
* PopUp 弹出层 |
|
* @description 弹出层组件,为了解决遮罩弹层的问题 |
|
* @tutorial https://ext.dcloud.net.cn/plugin?id=329 |
|
* @property {String} type = [top|center|bottom] 弹出方式 |
|
* @value top 顶部弹出 |
|
* @value center 中间弹出 |
|
* @value bottom 底部弹出 |
|
* @value message 消息提示 |
|
* @value dialog 对话框 |
|
* @value share 底部分享示例 |
|
* @property {Boolean} animation = [ture|false] 是否开启动画 |
|
* @property {Boolean} maskClick = [ture|false] 蒙版点击是否关闭弹窗 |
|
* @event {Function} change 打开关闭弹窗触发,e={show: false} |
|
*/ |
|
|
|
export default { |
|
name: 'UniPopup', |
|
components: { |
|
uniTransition |
|
}, |
|
props: { |
|
// 开启动画 |
|
animation: { |
|
type: Boolean, |
|
default: true |
|
}, |
|
// 弹出层类型,可选值,top: 顶部弹出层;bottom:底部弹出层;center:全屏弹出层 |
|
// message: 消息提示 ; dialog : 对话框 |
|
type: { |
|
type: String, |
|
default: 'center' |
|
}, |
|
// maskClick |
|
maskClick: { |
|
type: Boolean, |
|
default: true |
|
} |
|
}, |
|
provide() { |
|
return { |
|
popup: this |
|
} |
|
}, |
|
mixins: [popup], |
|
watch: { |
|
/** |
|
* 监听type类型 |
|
*/ |
|
type: { |
|
handler: function(newVal) { |
|
this[this.config[newVal]]() |
|
}, |
|
immediate: true |
|
}, |
|
/** |
|
* 监听遮罩是否可点击 |
|
* @param {Object} val |
|
*/ |
|
maskClick(val) { |
|
this.mkclick = val |
|
} |
|
}, |
|
data() { |
|
return { |
|
duration: 300, |
|
ani: [], |
|
showPopup: false, |
|
showTrans: false, |
|
maskClass: { |
|
'position': 'fixed', |
|
'bottom': 0, |
|
'top': 0, |
|
'left': 0, |
|
'right': 0, |
|
'backgroundColor': 'rgba(0, 0, 0, 0.4)' |
|
}, |
|
transClass: { |
|
'position': 'fixed', |
|
'left': 0, |
|
'right': 0, |
|
}, |
|
maskShow: true, |
|
mkclick: true, |
|
popupstyle: 'top' |
|
} |
|
}, |
|
created() { |
|
this.mkclick = this.maskClick |
|
if (this.animation) { |
|
this.duration = 300 |
|
} else { |
|
this.duration = 0 |
|
} |
|
}, |
|
methods: { |
|
clear(e) { |
|
// TODO nvue 取消冒泡 |
|
e.stopPropagation() |
|
}, |
|
open() { |
|
this.showPopup = true |
|
this.$nextTick(() => { |
|
new Promise(resolve => { |
|
clearTimeout(this.timer) |
|
this.timer = setTimeout(() => { |
|
this.showTrans = true |
|
// fixed by mehaotian 兼容 app 端 |
|
this.$nextTick(() => { |
|
resolve(); |
|
}) |
|
}, 50); |
|
}).then(res => { |
|
// 自定义打开事件 |
|
clearTimeout(this.msgtimer) |
|
this.msgtimer = setTimeout(() => { |
|
this.customOpen && this.customOpen() |
|
}, 100) |
|
this.$emit('change', { |
|
show: true, |
|
type: this.type |
|
}) |
|
}) |
|
}) |
|
}, |
|
close(type) { |
|
this.showTrans = false |
|
this.$nextTick(() => { |
|
this.$emit('change', { |
|
show: false, |
|
type: this.type |
|
}) |
|
clearTimeout(this.timer) |
|
// 自定义关闭事件 |
|
this.customOpen && this.customClose() |
|
this.timer = setTimeout(() => { |
|
this.showPopup = false |
|
}, 300) |
|
}) |
|
}, |
|
onTap() { |
|
if (!this.mkclick) return |
|
this.close() |
|
}, |
|
/** |
|
* 顶部弹出样式处理 |
|
*/ |
|
top() { |
|
this.popupstyle = 'top' |
|
this.ani = ['slide-top'] |
|
this.transClass = { |
|
'position': 'fixed', |
|
'left': 0, |
|
'right': 0, |
|
} |
|
}, |
|
/** |
|
* 底部弹出样式处理 |
|
*/ |
|
bottom() { |
|
this.popupstyle = 'bottom' |
|
this.ani = ['slide-bottom'] |
|
this.transClass = { |
|
'position': 'fixed', |
|
'left': 0, |
|
'right': 0, |
|
'bottom': 0 |
|
} |
|
}, |
|
/** |
|
* 中间弹出样式处理 |
|
*/ |
|
center() { |
|
this.popupstyle = 'center' |
|
this.ani = ['zoom-out', 'fade'] |
|
this.transClass = { |
|
'position': 'fixed', |
|
/* #ifndef APP-NVUE */ |
|
'display': 'flex', |
|
'flexDirection': 'column', |
|
/* #endif */ |
|
'bottom': 0, |
|
'left': 0, |
|
'right': 0, |
|
'top': 0, |
|
'justifyContent': 'center', |
|
'alignItems': 'center' |
|
} |
|
} |
|
} |
|
} |
|
</script> |
|
<style lang="scss" scoped> |
|
.uni-popup { |
|
position: fixed; |
|
/* #ifndef APP-NVUE */ |
|
z-index: 99; |
|
/* #endif */ |
|
} |
|
|
|
.uni-popup__mask { |
|
position: absolute; |
|
top: 0; |
|
bottom: 0; |
|
left: 0; |
|
right: 0; |
|
background-color: $uni-bg-color-mask; |
|
opacity: 0; |
|
} |
|
|
|
.mask-ani { |
|
transition-property: opacity; |
|
transition-duration: 0.2s; |
|
} |
|
|
|
.uni-top-mask { |
|
opacity: 1; |
|
} |
|
|
|
.uni-bottom-mask { |
|
opacity: 1; |
|
} |
|
|
|
.uni-center-mask { |
|
opacity: 1; |
|
} |
|
|
|
.uni-popup__wrapper { |
|
/* #ifndef APP-NVUE */ |
|
display: block; |
|
/* #endif */ |
|
position: absolute; |
|
} |
|
|
|
.top { |
|
/* #ifdef H5 */ |
|
top: var(--window-top); |
|
/* #endif */ |
|
/* #ifndef H5 */ |
|
top: 0; |
|
/* #endif */ |
|
} |
|
|
|
.bottom { |
|
bottom: 0; |
|
} |
|
|
|
.uni-popup__wrapper-box { |
|
/* #ifndef APP-NVUE */ |
|
display: block; |
|
/* #endif */ |
|
position: relative; |
|
/* iphonex 等安全区设置,底部安全区适配 */ |
|
/* #ifndef APP-NVUE */ |
|
padding-bottom: constant(safe-area-inset-bottom); |
|
padding-bottom: env(safe-area-inset-bottom); |
|
/* #endif */ |
|
} |
|
|
|
.content-ani { |
|
// transition: transform 0.3s; |
|
transition-property: transform, opacity; |
|
transition-duration: 0.2s; |
|
} |
|
|
|
|
|
.uni-top-content { |
|
transform: translateY(0); |
|
} |
|
|
|
.uni-bottom-content { |
|
transform: translateY(0); |
|
} |
|
|
|
.uni-center-content { |
|
transform: scale(1); |
|
opacity: 1; |
|
} |
|
</style>
|
|
|