421 lines
9.4 KiB
Vue
421 lines
9.4 KiB
Vue
|
<template>
|
||
|
<view v-if="isShow">
|
||
|
<view
|
||
|
@tap.stop.prevent
|
||
|
@touchmove.stop.prevent
|
||
|
class="wyb-popup-box"
|
||
|
:style="{
|
||
|
transitionDuration: duration + 'ms',
|
||
|
opacity: contentOpacity || (type === 'center' ? 0 : 1),
|
||
|
transform: contentTransform || autoTransform,
|
||
|
zIndex: zIndex,
|
||
|
borderTopRightRadius: type === 'center' || type === 'bottom' || type === 'left' ? radius + 'px' : 0,
|
||
|
borderTopLeftRadius: type === 'center' || type === 'bottom' || type === 'right' ? radius + 'px' : 0,
|
||
|
borderBottomRightRadius: type === 'center' || type === 'top' || type === 'left' ? radius + 'px' : 0,
|
||
|
borderBottomLeftRadius: type === 'center' || type === 'top' || type === 'right' ? radius + 'px' : 0,
|
||
|
width: autoWidth,
|
||
|
height: autoHeight,
|
||
|
minWidth: width + 'rpx',
|
||
|
minHeight: height + 'rpx',
|
||
|
top: sizeChange && type === 'center' ? winReTop : autoTop,
|
||
|
bottom: autoBottom,
|
||
|
left: autoLeft,
|
||
|
right: autoRight,
|
||
|
backgroundColor: bgColor}">
|
||
|
<view
|
||
|
class="wyb-popup-close"
|
||
|
v-if="showCloseIcon"
|
||
|
:style="{
|
||
|
width: closeIcon ? closeIconSize + 'rpx' : 'auto',
|
||
|
height: closeIcon ? closeIconSize + 'rpx' : 'auto',
|
||
|
top: closeIconPos === 'top-right' || closeIconPos === 'top-left' ? vertOffset + 'rpx' : 'auto',
|
||
|
bottom: closeIconPos === 'bottom-right' || closeIconPos === 'bottom-left' ? vertOffset + 'rpx' : 'auto',
|
||
|
left: closeIconPos === 'bottom-left' || closeIconPos === 'top-left' ? horiOffset + 'rpx' : 'auto',
|
||
|
right: closeIconPos === 'bottom-right' || closeIconPos === 'top-right' ? horiOffset + 'rpx' : 'auto'}">
|
||
|
<image class="wyb-popup-custom-close" v-if="showCloseIcon&&closeIcon" :src="closeIcon" @tap="hide" :style="{
|
||
|
width: closeIconSize + 'rpx',
|
||
|
height: closeIconSize + 'rpx'}" />
|
||
|
<view v-if="showCloseIcon&&!closeIcon" class="iconfont icon-close" @tap="hide" />
|
||
|
</view>
|
||
|
|
||
|
<scroll-view
|
||
|
class="wyb-popup-container"
|
||
|
:style="{
|
||
|
width: autoWidth,
|
||
|
height: autoHeight}"
|
||
|
:enable-flex="true"
|
||
|
:scroll-y="scrollY"
|
||
|
:scroll-x="scrollX">
|
||
|
<view class="wyb-popup-slot"><slot></slot></view>
|
||
|
</scroll-view>
|
||
|
</view>
|
||
|
<view
|
||
|
class="wyb-popup-mask"
|
||
|
@tap.stop="close"
|
||
|
@touchmove.stop.prevent
|
||
|
:style="{
|
||
|
opacity: maskOpacity,
|
||
|
transitionDuration: duration + 'ms',
|
||
|
backgroundColor: 'rgba(0, 0, 0, ' + maskAlpha + ')',
|
||
|
zIndex: zIndex - 1}" />
|
||
|
</view>
|
||
|
</template>
|
||
|
|
||
|
<script>
|
||
|
export default {
|
||
|
data() {
|
||
|
return {
|
||
|
w: uni.getSystemInfoSync().screenWidth,
|
||
|
h: uni.getSystemInfoSync().screenHeight,
|
||
|
isShow: false,
|
||
|
winReBottom: '',
|
||
|
winReTop: '',
|
||
|
sizeChange: false,
|
||
|
contentOpacity: null,
|
||
|
contentTransform: null,
|
||
|
maskOpacity: 0
|
||
|
}
|
||
|
},
|
||
|
computed: {
|
||
|
autoCenterTop() {
|
||
|
let statusBarHeight = uni.getSystemInfoSync().statusBarHeight
|
||
|
let windowHeight = uni.getSystemInfoSync().windowHeight
|
||
|
let popupHeight = this.rpxToPx(this.height)
|
||
|
let navHeight = 44
|
||
|
let result = `${(windowHeight - popupHeight) / 2 - this.negativeTop}px`
|
||
|
return result
|
||
|
},
|
||
|
autoTransform() {
|
||
|
let result = ''
|
||
|
switch(this.type) {
|
||
|
case 'center':
|
||
|
if (this.centerAnim === 'zoom-lessen') {
|
||
|
result = `scale(${this.zoomLessenMulti})`
|
||
|
} else if (this.centerAnim === 'slide-up') {
|
||
|
result = `translateY(${100 * this.slideMulti}%)`
|
||
|
} else if (this.centerAnim === 'slide-down') {
|
||
|
result = `translateY(${-100 * this.slideMulti}%)`
|
||
|
} else if (this.centerAnim === 'fade') {
|
||
|
result = 'auto'
|
||
|
}
|
||
|
break
|
||
|
case 'bottom':
|
||
|
result = 'translateY(100%)'
|
||
|
break
|
||
|
case 'top':
|
||
|
result = 'translateY(-100%)'
|
||
|
break
|
||
|
case 'left':
|
||
|
result = 'translateX(-100%)'
|
||
|
break
|
||
|
case 'right':
|
||
|
result = 'translateX(100%)'
|
||
|
break
|
||
|
}
|
||
|
return result
|
||
|
},
|
||
|
autoWidth() {
|
||
|
if (this.type === 'center') {
|
||
|
return `${this.width}rpx`
|
||
|
} else {
|
||
|
if (this.mode === 'size-fixed') {
|
||
|
if (this.type === 'top' || this.type === 'bottom') {
|
||
|
return '100%'
|
||
|
} else {
|
||
|
return `${this.width}rpx`
|
||
|
}
|
||
|
} else {
|
||
|
if (this.type === 'top' || this.type === 'bottom') {
|
||
|
return '100%'
|
||
|
} else {
|
||
|
return 'auto'
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
},
|
||
|
autoHeight() {
|
||
|
if (this.type === 'center') {
|
||
|
return `${this.height}rpx`
|
||
|
} else {
|
||
|
if (this.mode === 'size-fixed') {
|
||
|
if (this.type === 'left' || this.type === 'right') {
|
||
|
return '100%'
|
||
|
} else {
|
||
|
return `${this.height}rpx`
|
||
|
}
|
||
|
} else {
|
||
|
if (this.type === 'left' || this.type === 'right') {
|
||
|
return '100%'
|
||
|
} else {
|
||
|
return 'auto'
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
},
|
||
|
autoTop() {
|
||
|
if (this.type === 'center') {
|
||
|
return this.autoCenterTop
|
||
|
} else if (this.type === 'bottom') {
|
||
|
return 'auto'
|
||
|
} else {
|
||
|
return 0
|
||
|
}
|
||
|
},
|
||
|
autoBottom() {
|
||
|
if (this.type === 'center' || this.type === 'top') {
|
||
|
return 'auto'
|
||
|
} else {
|
||
|
return 0
|
||
|
}
|
||
|
},
|
||
|
autoLeft() {
|
||
|
if (this.type === 'center') {
|
||
|
return `${(this.w - this.rpxToPx(this.width)) / 2}px`
|
||
|
} else if (this.type === 'right') {
|
||
|
return 'auto'
|
||
|
} else {
|
||
|
return 0
|
||
|
}
|
||
|
},
|
||
|
autoRight() {
|
||
|
if (this.type === 'center' || this.type === 'left') {
|
||
|
return 'auto'
|
||
|
} else {
|
||
|
return 0
|
||
|
}
|
||
|
}
|
||
|
},
|
||
|
props: {
|
||
|
type: {
|
||
|
type: String,
|
||
|
default: 'bottom'
|
||
|
},
|
||
|
mode: {
|
||
|
type: String,
|
||
|
default: 'size-auto'
|
||
|
},
|
||
|
height: {
|
||
|
type: [String, Number],
|
||
|
default: 400
|
||
|
},
|
||
|
width: {
|
||
|
type: [String, Number],
|
||
|
default: 500
|
||
|
},
|
||
|
radius: {
|
||
|
type: [String, Number],
|
||
|
default: 0
|
||
|
},
|
||
|
zIndex: {
|
||
|
type: [String, Number],
|
||
|
default: 10076
|
||
|
},
|
||
|
maskClickClose: {
|
||
|
type: Boolean,
|
||
|
default: true
|
||
|
},
|
||
|
maskAlpha: {
|
||
|
type: Number,
|
||
|
default: 0.5
|
||
|
},
|
||
|
duration: {
|
||
|
type: Number,
|
||
|
default: 400
|
||
|
},
|
||
|
showCloseIcon: {
|
||
|
type: Boolean,
|
||
|
default: false
|
||
|
},
|
||
|
scrollY: {
|
||
|
type: Boolean,
|
||
|
default: false
|
||
|
},
|
||
|
scrollX: {
|
||
|
type: Boolean,
|
||
|
default: false
|
||
|
},
|
||
|
closeIconPos: {
|
||
|
type: String,
|
||
|
default: 'top-right'
|
||
|
},
|
||
|
closeIcon: {
|
||
|
type: String,
|
||
|
default: ''
|
||
|
},
|
||
|
closeIconSize: {
|
||
|
type: [String, Number],
|
||
|
default: '20'
|
||
|
},
|
||
|
vertOffset: {
|
||
|
type: [String, Number],
|
||
|
default: '22'
|
||
|
},
|
||
|
horiOffset: {
|
||
|
type: [String, Number],
|
||
|
default: '22'
|
||
|
},
|
||
|
centerAnim: {
|
||
|
type: String,
|
||
|
default: 'zoom-lessen'
|
||
|
},
|
||
|
bgColor: {
|
||
|
type: String,
|
||
|
default: '#ffffff'
|
||
|
},
|
||
|
zoomLessenMulti: {
|
||
|
type: Number,
|
||
|
default: 1.15
|
||
|
},
|
||
|
slideMulti: {
|
||
|
type: Number,
|
||
|
default: 1
|
||
|
},
|
||
|
negativeTop: {
|
||
|
type: Number,
|
||
|
default: 0
|
||
|
}
|
||
|
},
|
||
|
mounted() {
|
||
|
// #ifdef H5
|
||
|
let winHeight = uni.getSystemInfoSync().windowHeight
|
||
|
uni.onWindowResize(res => {
|
||
|
this.sizeChange = true
|
||
|
if (this.type === 'bottom') {
|
||
|
this.winReBottom = winHeight - res.size.windowHeight + 'px'
|
||
|
} else if (this.type === 'center') {
|
||
|
this.winReTop = ((res.size.windowHeight - this.rpxToPx(this.height)) / 2 - this.negativeTop) + 'px'
|
||
|
}
|
||
|
})
|
||
|
// #endif
|
||
|
},
|
||
|
methods: {
|
||
|
close() {
|
||
|
this.maskClickClose && this.hide()
|
||
|
},
|
||
|
show() {
|
||
|
this.isShow = true
|
||
|
// #ifndef H5
|
||
|
this.$nextTick(() => {
|
||
|
this.maskIn()
|
||
|
this.contentIn()
|
||
|
this.wait(this.duration + 1).then(() => {
|
||
|
this.$emit('show', {
|
||
|
pageScroll: false,
|
||
|
overflow: 'hidden'
|
||
|
})
|
||
|
})
|
||
|
})
|
||
|
// #endif
|
||
|
// #ifdef H5
|
||
|
this.wait(10).then(() => {
|
||
|
this.maskIn()
|
||
|
this.contentIn()
|
||
|
this.wait(this.duration + 1).then(() => {
|
||
|
this.$emit('show', {
|
||
|
pageScroll: false,
|
||
|
overflow: 'hidden'
|
||
|
})
|
||
|
})
|
||
|
})
|
||
|
// #endif
|
||
|
},
|
||
|
hide() {
|
||
|
this.contentOut()
|
||
|
this.maskOut()
|
||
|
this.wait(this.duration + 1).then(() => {
|
||
|
this.isShow = false
|
||
|
this.$emit('hide', {
|
||
|
pageScroll: true,
|
||
|
overflow: 'scroll'
|
||
|
})
|
||
|
})
|
||
|
},
|
||
|
contentIn() {
|
||
|
switch (this.type) {
|
||
|
case 'center':
|
||
|
if (this.centerAnim === 'zoom-lessen') {
|
||
|
this.contentOpacity = 1
|
||
|
this.contentTransform = 'scale(1)'
|
||
|
} else if (this.centerAnim === 'slide-up' || this.centerAnim === 'slide-down') {
|
||
|
this.contentOpacity = 1
|
||
|
this.contentTransform = 'translateY(0)'
|
||
|
} else if (this.centerAnim === 'fade') {
|
||
|
this.contentOpacity = 1
|
||
|
}
|
||
|
break
|
||
|
case 'bottom':
|
||
|
case 'top':
|
||
|
this.contentTransform = 'translateY(0)'
|
||
|
break
|
||
|
case 'left':
|
||
|
case 'right':
|
||
|
this.contentTransform = 'translateX(0)'
|
||
|
break
|
||
|
}
|
||
|
},
|
||
|
contentOut() {
|
||
|
this.contentOpacity = null
|
||
|
this.contentTransform = null
|
||
|
},
|
||
|
maskIn() {
|
||
|
this.maskOpacity = 1
|
||
|
},
|
||
|
maskOut() {
|
||
|
this.maskOpacity = 0
|
||
|
},
|
||
|
rpxToPx(rpx) {
|
||
|
return rpx / 750 * this.w
|
||
|
},
|
||
|
wait(time) {
|
||
|
return new Promise(resolve => {
|
||
|
setTimeout(() => {
|
||
|
resolve()
|
||
|
}, time)
|
||
|
})
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
</script>
|
||
|
|
||
|
<style>
|
||
|
@import "./iconfont.css";
|
||
|
.wyb-popup-box{
|
||
|
position: fixed;
|
||
|
transition-timing-function: ease-out;
|
||
|
transition-property: opacity, transform;
|
||
|
}
|
||
|
|
||
|
.wyb-popup-container {
|
||
|
position: relative;
|
||
|
box-sizing: border-box;
|
||
|
}
|
||
|
|
||
|
.wyb-popup-slot {
|
||
|
width: 100%;
|
||
|
height: 100%;
|
||
|
}
|
||
|
|
||
|
.wyb-popup-mask {
|
||
|
position: fixed;
|
||
|
top: 0;
|
||
|
left: 0;
|
||
|
bottom: 0;
|
||
|
right: 0;
|
||
|
transition-timing-function: ease;
|
||
|
transition-property: opacity, transform;
|
||
|
}
|
||
|
|
||
|
.wyb-popup-close {
|
||
|
position: absolute;
|
||
|
fontSize: 40rpx;
|
||
|
color: #808080;
|
||
|
z-index: 20000;
|
||
|
}
|
||
|
|
||
|
.wyb-popup-custom-close {
|
||
|
left: 0;
|
||
|
top: 0;
|
||
|
position: absolute;
|
||
|
}
|
||
|
</style>
|