| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302 | <template>	<view v-if="showPopupState" class="uni-popup" :class="[popupstyle]" @touchmove.stop.prevent="clear">		<uni-transition v-if="maskShow" :mode-class="['fade']" :styles="maskClass" :maskBackgroundColor="maskBackgroundColor" :duration="duration" :show="showTrans"		 @click="onTap" />		<uni-transition :mode-class="ani" :styles="transClass" maskBackgroundColor="rgba(,0,0,0,0)" :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'	/**	 * 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			},			maskBackgroundColor: {				type: String,				default: 'rgba(0, 0, 0, .5)'			}		},		provide() {			return {				popup: this			}		},		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: [],				showPopupState: false,				showTrans: false,				maskClass: {					'position': 'fixed',					'bottom': 0,					'top': 0,					'left': 0,					'right': 0				},				transClass: {					'position': 'fixed',					'left': 0,					'right': 0,				},				maskShow: true,				mkclick: true,				popupstyle: 'top',				config: {					top:'top',					// 底部弹出					bottom:'bottom',					// 居中弹出					center:'center'				}			}		},		created() {			this.mkclick = this.maskClick			if (this.animation) {				this.duration = 300			} else {				this.duration = 0			}		},		methods: {			clear(e) {				// TODO nvue 取消冒泡				e.stopPropagation()			},			open() {				this.showPopupState = 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.showPopupState = 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>
 |