2018-03-26 16:04:04 +08:00
|
|
|
<template>
|
|
|
|
<div
|
|
|
|
v-show="isPopupShow"
|
|
|
|
class="md-popup"
|
|
|
|
:class="[
|
|
|
|
hasMask ? 'with-mask' : '',
|
|
|
|
position
|
|
|
|
]"
|
|
|
|
>
|
2018-09-14 22:27:20 +08:00
|
|
|
<transition name="md-mask-fade">
|
2018-03-26 16:04:04 +08:00
|
|
|
<div
|
|
|
|
v-show="hasMask && isPopupBoxShow"
|
|
|
|
@click="$_onPopupMaskClick"
|
|
|
|
class="md-popup-mask"
|
|
|
|
></div>
|
|
|
|
</transition>
|
2018-09-14 22:27:20 +08:00
|
|
|
<md-transition
|
2018-03-26 16:04:04 +08:00
|
|
|
:name="transition"
|
|
|
|
@before-enter="$_onPopupTransitionStart"
|
|
|
|
@before-leave="$_onPopupTransitionStart"
|
|
|
|
@after-enter="$_onPopupTransitionEnd"
|
|
|
|
@after-leave="$_onPopupTransitionEnd"
|
|
|
|
>
|
|
|
|
<div
|
|
|
|
v-show="isPopupBoxShow"
|
|
|
|
class="md-popup-box"
|
|
|
|
:class="[
|
|
|
|
transition
|
|
|
|
]"
|
|
|
|
>
|
|
|
|
<slot></slot>
|
|
|
|
</div>
|
2018-09-14 22:27:20 +08:00
|
|
|
</md-transition>
|
2018-03-26 16:04:04 +08:00
|
|
|
</div>
|
|
|
|
</template>
|
|
|
|
|
2018-09-14 22:27:20 +08:00
|
|
|
<script>
import Transition from '../transition'
|
2018-12-12 14:11:25 +08:00
|
|
|
import popupMixin from './mixins'
|
2018-09-14 22:27:20 +08:00
|
|
|
|
|
|
|
export default {
|
2018-03-26 16:04:04 +08:00
|
|
|
name: 'md-popup',
|
|
|
|
|
2018-12-12 14:11:25 +08:00
|
|
|
mixins: [popupMixin],
|
|
|
|
|
2018-09-14 22:27:20 +08:00
|
|
|
components: {
|
|
|
|
'md-transition': Transition,
|
|
|
|
},
|
|
|
|
|
2018-03-26 16:04:04 +08:00
|
|
|
props: {
|
|
|
|
position: {
|
|
|
|
type: String,
|
|
|
|
default: 'center',
|
|
|
|
},
|
|
|
|
transition: {
|
|
|
|
type: String,
|
|
|
|
default() {
|
|
|
|
switch (this.position) {
|
|
|
|
case 'bottom':
|
2018-09-14 22:27:20 +08:00
|
|
|
return 'md-slide-up'
|
2018-03-26 16:04:04 +08:00
|
|
|
/* istanbul ignore next */
|
|
|
|
case 'top':
|
2018-09-14 22:27:20 +08:00
|
|
|
return 'md-slide-down'
|
2018-03-26 16:04:04 +08:00
|
|
|
/* istanbul ignore next */
|
|
|
|
case 'left':
|
2018-09-14 22:27:20 +08:00
|
|
|
return 'md-slide-right'
|
2018-03-26 16:04:04 +08:00
|
|
|
/* istanbul ignore next */
|
|
|
|
case 'right':
|
2018-09-14 22:27:20 +08:00
|
|
|
return 'md-slide-left'
|
2018-03-26 16:04:04 +08:00
|
|
|
default:
|
2018-09-14 22:27:20 +08:00
|
|
|
return 'md-fade' // fade/fade-bounce/fade-slide/fade-zoom
|
2018-03-26 16:04:04 +08:00
|
|
|
}
|
|
|
|
},
|
|
|
|
},
|
|
|
|
preventScroll: {
|
|
|
|
type: Boolean,
|
|
|
|
default: false,
|
|
|
|
},
|
|
|
|
preventScrollExclude: {
|
2018-12-06 16:28:45 +08:00
|
|
|
type: [String, Function],
|
2018-03-26 16:04:04 +08:00
|
|
|
default() {
|
|
|
|
return ''
|
|
|
|
},
|
|
|
|
},
|
2018-12-12 14:11:25 +08:00
|
|
|
// Mixin Props
|
|
|
|
// value: {
|
|
|
|
// type: Boolean,
|
|
|
|
// default: false,
|
|
|
|
// },
|
|
|
|
// hasMask: {
|
|
|
|
// type: Boolean,
|
|
|
|
// default: true,
|
|
|
|
// },
|
|
|
|
// maskClosable: {
|
|
|
|
// type: Boolean,
|
|
|
|
// default: true,
|
|
|
|
// },
|
2018-03-26 16:04:04 +08:00
|
|
|
},
|
|
|
|
|
|
|
|
data() {
|
|
|
|
return {
|
|
|
|
// controle popup mask & popup box
|
|
|
|
isPopupShow: false,
|
|
|
|
// controle popup box
|
|
|
|
isPopupBoxShow: false,
|
|
|
|
// transtion lock
|
|
|
|
isAnimation: false,
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
watch: {
|
|
|
|
value(val) {
|
|
|
|
/* istanbul ignore next */
|
|
|
|
if (val) {
|
|
|
|
if (this.isAnimation) {
|
|
|
|
setTimeout(() => {
|
|
|
|
this.$_showPopupBox()
|
|
|
|
}, 50)
|
|
|
|
} else {
|
|
|
|
this.$_showPopupBox()
|
|
|
|
}
|
|
|
|
} else {
|
2018-12-19 13:22:50 +08:00
|
|
|
this.$_hidePopupBox()
|
2018-03-26 16:04:04 +08:00
|
|
|
}
|
|
|
|
},
|
2018-04-20 14:11:57 +08:00
|
|
|
preventScrollExclude(val, oldVal) {
|
|
|
|
// remove old listener before add
|
2018-04-23 17:33:32 +08:00
|
|
|
/* istanbul ignore next */
|
2018-04-20 14:11:57 +08:00
|
|
|
this.$_preventScrollExclude(false, oldVal)
|
2018-04-23 17:33:32 +08:00
|
|
|
/* istanbul ignore next */
|
2018-04-20 14:11:57 +08:00
|
|
|
this.$_preventScrollExclude(true, val)
|
|
|
|
},
|
2018-03-26 16:04:04 +08:00
|
|
|
},
|
|
|
|
|
|
|
|
mounted() {
|
|
|
|
this.value && this.$_showPopupBox()
|
|
|
|
},
|
|
|
|
|
|
|
|
methods: {
|
|
|
|
// MARK: private methods
|
|
|
|
$_showPopupBox() {
|
|
|
|
this.isPopupShow = true
|
|
|
|
this.isAnimation = true
|
|
|
|
// popup box enter the animation after popup show
|
|
|
|
this.$nextTick(() => {
|
|
|
|
this.isPopupBoxShow = true
|
2018-04-23 17:33:32 +08:00
|
|
|
/* istanbul ignore if */
|
2018-12-09 20:36:47 +08:00
|
|
|
if (process.env.NODE_ENV === 'test') {
|
2019-01-26 22:28:11 +08:00
|
|
|
this.$_onPopupTransitionStart()
|
2018-03-26 16:04:04 +08:00
|
|
|
this.$_onPopupTransitionEnd()
|
|
|
|
}
|
|
|
|
})
|
2018-04-20 14:11:57 +08:00
|
|
|
|
2018-03-26 16:04:04 +08:00
|
|
|
this.preventScroll && this.$_preventScroll(true)
|
|
|
|
},
|
|
|
|
$_hidePopupBox() {
|
|
|
|
this.isAnimation = true
|
2018-12-01 03:11:58 +08:00
|
|
|
this.isPopupBoxShow = false
|
|
|
|
this.preventScroll && this.$_preventScroll(false)
|
|
|
|
this.$emit('input', false)
|
|
|
|
/* istanbul ignore if */
|
2018-12-09 20:36:47 +08:00
|
|
|
if (process.env.NODE_ENV === 'test') {
|
2019-01-26 22:28:11 +08:00
|
|
|
this.$_onPopupTransitionStart()
|
2018-12-01 03:11:58 +08:00
|
|
|
this.$_onPopupTransitionEnd()
|
|
|
|
}
|
2018-03-26 16:04:04 +08:00
|
|
|
},
|
|
|
|
$_preventScroll(isBind) {
|
|
|
|
const handler = isBind ? 'addEventListener' : 'removeEventListener'
|
2018-04-20 14:11:57 +08:00
|
|
|
const masker = this.$el.querySelector('.md-popup-mask')
|
|
|
|
const boxer = this.$el.querySelector('.md-popup-box')
|
|
|
|
|
|
|
|
masker && masker[handler]('touchmove', this.$_preventDefault, false)
|
|
|
|
boxer && boxer[handler]('touchmove', this.$_preventDefault, false)
|
|
|
|
this.$_preventScrollExclude(isBind)
|
|
|
|
},
|
|
|
|
$_preventScrollExclude(isBind, preventScrollExclude) {
|
|
|
|
const handler = isBind ? 'addEventListener' : 'removeEventListener'
|
|
|
|
preventScrollExclude = preventScrollExclude || this.preventScrollExclude
|
2018-03-26 16:04:04 +08:00
|
|
|
const excluder =
|
|
|
|
preventScrollExclude && typeof preventScrollExclude === 'string'
|
|
|
|
? this.$el.querySelector(preventScrollExclude)
|
|
|
|
: preventScrollExclude
|
|
|
|
excluder && excluder[handler]('touchmove', this.$_stopImmediatePropagation, false)
|
|
|
|
},
|
|
|
|
$_preventDefault(event) {
|
|
|
|
event.preventDefault()
|
|
|
|
},
|
|
|
|
$_stopImmediatePropagation(event) {
|
2018-04-23 17:33:32 +08:00
|
|
|
/* istanbul ignore next */
|
2018-03-26 16:04:04 +08:00
|
|
|
event.stopImmediatePropagation()
|
|
|
|
},
|
|
|
|
|
|
|
|
// MARK: event handler
|
|
|
|
$_onPopupTransitionStart() {
|
|
|
|
if (!this.isPopupBoxShow) {
|
|
|
|
this.$emit('beforeHide')
|
|
|
|
this.$emit('before-hide')
|
|
|
|
} else {
|
|
|
|
this.$emit('beforeShow')
|
|
|
|
this.$emit('before-show')
|
|
|
|
}
|
|
|
|
},
|
|
|
|
$_onPopupTransitionEnd() {
|
|
|
|
/* istanbul ignore next */
|
|
|
|
if (!this.isAnimation) {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
/* istanbul ignore next */
|
|
|
|
if (!this.isPopupBoxShow) {
|
|
|
|
// popup hide after popup box finish animation
|
|
|
|
this.isPopupShow = false
|
|
|
|
this.$emit('hide')
|
|
|
|
} else {
|
|
|
|
this.$emit('show')
|
|
|
|
}
|
|
|
|
|
|
|
|
/* istanbul ignore next */
|
|
|
|
this.isAnimation = false
|
|
|
|
},
|
|
|
|
$_onPopupMaskClick() {
|
2018-05-29 00:11:05 +08:00
|
|
|
if (this.maskClosable) {
|
|
|
|
this.$_hidePopupBox()
|
|
|
|
this.$emit('maskClick')
|
|
|
|
}
|
2018-03-26 16:04:04 +08:00
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
</script>
|
|
|
|
|
|
|
|
<style lang="stylus">
|
|
|
|
.md-popup
|
2018-09-14 22:27:20 +08:00
|
|
|
absolute-pos()
|
|
|
|
position fixed
|
|
|
|
display flex
|
|
|
|
pointer-events none
|
|
|
|
z-index popup-zindex
|
|
|
|
|
|
|
|
&.center
|
|
|
|
align-items center
|
|
|
|
justify-content center
|
|
|
|
|
|
|
|
&.top
|
|
|
|
flex-direction column
|
|
|
|
justify-content flex-start
|
2018-03-26 16:04:04 +08:00
|
|
|
.md-popup-box
|
2018-09-14 22:27:20 +08:00
|
|
|
width 100%
|
|
|
|
|
|
|
|
&.bottom
|
|
|
|
flex-direction column
|
|
|
|
justify-content flex-end
|
2018-03-26 16:04:04 +08:00
|
|
|
.md-popup-box
|
|
|
|
width 100%
|
2018-09-14 22:27:20 +08:00
|
|
|
|
|
|
|
&.left
|
|
|
|
justify-content flex-start
|
|
|
|
.md-popup-box
|
|
|
|
height 100%
|
|
|
|
|
|
|
|
&.right
|
|
|
|
justify-content flex-end
|
2018-03-26 16:04:04 +08:00
|
|
|
.md-popup-box
|
|
|
|
height 100%
|
|
|
|
|
2018-12-06 16:23:15 +08:00
|
|
|
&.inner-popup .md-popup-box
|
|
|
|
background-color color-bg-inverse
|
|
|
|
border-radius popup-title-bar-radius popup-title-bar-radius 0 0
|
|
|
|
|
2018-09-03 16:51:17 +08:00
|
|
|
.md-popup-mask
|
|
|
|
absolute-pos()
|
|
|
|
position absolute
|
2018-09-14 22:27:20 +08:00
|
|
|
pointer-events auto
|
2018-09-03 16:51:17 +08:00
|
|
|
z-index 1
|
|
|
|
background-color popup-mask-bg
|
|
|
|
|
|
|
|
.md-popup-box
|
2018-09-14 22:27:20 +08:00
|
|
|
position relative
|
|
|
|
pointer-events auto
|
|
|
|
z-index 2
|
2018-09-03 16:51:17 +08:00
|
|
|
max-width 100%
|
|
|
|
max-height 100%
|
|
|
|
overflow auto
|
2018-08-30 16:04:31 +08:00
|
|
|
|
2018-09-14 22:27:20 +08:00
|
|
|
.md-mask-fade
|
|
|
|
&-enter, &-leave-to
|
|
|
|
opacity 0.01
|
|
|
|
&-enter-active, &-leave-active
|
2018-09-24 15:48:57 +08:00
|
|
|
transition opacity 250ms
|
2018-03-26 16:04:04 +08:00
|
|
|
</style>
|