New file |
| | |
| | | <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> |