mirror of
				https://gitee.com/hhyykk/ipms-sjy.git
				synced 2025-10-31 10:18:42 +08:00 
			
		
		
		
	
		
			
	
	
		
			303 lines
		
	
	
		
			5.9 KiB
		
	
	
	
		
			Vue
		
	
	
	
	
	
		
		
			
		
	
	
			303 lines
		
	
	
		
			5.9 KiB
		
	
	
	
		
			Vue
		
	
	
	
	
	
|   | <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> |