mand-mobile/components/popup/index.vue

287 lines
6.5 KiB
Vue
Raw Normal View History

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'
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',
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: {
type: [String, Function],
2018-03-26 16:04:04 +08:00
default() {
return ''
},
},
// 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
}
},
preventScrollExclude(val, oldVal) {
// remove old listener before add
2018-04-23 17:33:32 +08:00
/* istanbul ignore next */
this.$_preventScrollExclude(false, oldVal)
2018-04-23 17:33:32 +08:00
/* istanbul ignore next */
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.isPopupBoxShow = true
/* istanbul ignore if */
if (process.env.NODE_ENV === 'test') {
this.$_onPopupTransitionStart()
this.$_onPopupTransitionEnd()
}
2018-03-26 16:04:04 +08:00
this.preventScroll && this.$_preventScroll(true)
},
$_hidePopupBox() {
this.isAnimation = true
this.isPopupBoxShow = false
this.preventScroll && this.$_preventScroll(false)
this.$emit('input', false)
/* istanbul ignore if */
if (process.env.NODE_ENV === 'test') {
2019-01-26 22:28:11 +08:00
this.$_onPopupTransitionStart()
this.$_onPopupTransitionEnd()
}
2018-03-26 16:04:04 +08:00
},
$_preventScroll(isBind) {
const handler = isBind ? 'addEventListener' : 'removeEventListener'
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() {
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%
&.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-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>