mirror of
				https://gitee.com/hhyykk/ipms-sjy.git
				synced 2025-11-01 02:38:43 +08:00 
			
		
		
		
	
		
			
	
	
		
			291 lines
		
	
	
		
			5.9 KiB
		
	
	
	
		
			Vue
		
	
	
	
	
	
		
		
			
		
	
	
			291 lines
		
	
	
		
			5.9 KiB
		
	
	
	
		
			Vue
		
	
	
	
	
	
|   | <template> | |||
|  | 	<view  | |||
|  | 		v-if="isShow"  | |||
|  | 		ref="ani"  | |||
|  | 		class="uni-transition"  | |||
|  | 		:class="[ani.in]"  | |||
|  | 		:style="'transform:' +transform+';'+stylesObject" | |||
|  | 		@click="change" | |||
|  | 	> | |||
|  | 		 <slot></slot> | |||
|  | 	</view> | |||
|  | </template> | |||
|  | 
 | |||
|  | <script> | |||
|  | 	// #ifdef APP-NVUE
 | |||
|  | 	const animation = uni.requireNativePlugin('animation'); | |||
|  | 	// #endif
 | |||
|  | 	/** | |||
|  | 	 * Transition 过渡动画 | |||
|  | 	 * @description 简单过渡动画组件 | |||
|  | 	 * @tutorial https://ext.dcloud.net.cn/plugin?id=985
 | |||
|  | 	 * @property {Boolean} show = [false|true] 控制组件显示或隐藏 | |||
|  |      * @property {Array} modeClass = [fade|slide-top|slide-right|slide-bottom|slide-left|zoom-in|zoom-out] 过渡动画类型 | |||
|  |      *  @value fade 渐隐渐出过渡 | |||
|  |      *  @value slide-top 由上至下过渡 | |||
|  |      *  @value slide-right 由右至左过渡 | |||
|  |      *  @value slide-bottom 由下至上过渡 | |||
|  |      *  @value slide-left 由左至右过渡 | |||
|  |      *  @value zoom-in 由小到大过渡 | |||
|  |      *  @value zoom-out 由大到小过渡 | |||
|  | 	 * @property {Number} duration 过渡动画持续时间 | |||
|  | 	 * @property {Object} styles 组件样式,同 css 样式,注意带’-‘连接符的属性需要使用小驼峰写法如:`backgroundColor:red` | |||
|  | 	 */ | |||
|  | 	export default { | |||
|  | 		name: 'uniTransition', | |||
|  | 		props: { | |||
|  | 			show: { | |||
|  | 				type: Boolean, | |||
|  | 				default: false | |||
|  | 			}, | |||
|  | 			modeClass: { | |||
|  | 				type: Array, | |||
|  | 				default () { | |||
|  | 					return [] | |||
|  | 				} | |||
|  | 			}, | |||
|  | 			duration: { | |||
|  | 				type: Number, | |||
|  | 				default: 300 | |||
|  | 			}, | |||
|  | 			styles: { | |||
|  | 				type: Object, | |||
|  | 				default () { | |||
|  | 					return {} | |||
|  | 				} | |||
|  | 			}, | |||
|  | 			maskBackgroundColor: { | |||
|  | 				type: String, | |||
|  | 				default: 'rgba(0, 0, 0, 0.4)' | |||
|  | 			} | |||
|  | 		}, | |||
|  | 		data() { | |||
|  | 			return { | |||
|  | 				isShow: false, | |||
|  | 				transform: '', | |||
|  | 				ani: { in: '', | |||
|  | 					active: '' | |||
|  | 				} | |||
|  | 			}; | |||
|  | 		}, | |||
|  | 		watch: { | |||
|  | 			show: { | |||
|  | 				handler(newVal) { | |||
|  | 					if (newVal) { | |||
|  | 						this.open() | |||
|  | 					} else { | |||
|  | 						this.close() | |||
|  | 					} | |||
|  | 				}, | |||
|  | 				immediate: true | |||
|  | 			} | |||
|  | 		}, | |||
|  | 		computed: { | |||
|  | 			stylesObject() { | |||
|  | 				let styles = { | |||
|  | 					...this.styles, | |||
|  | 					backgroundColor: this.maskBackgroundColor, | |||
|  | 					'transition-duration': this.duration / 1000 + 's' | |||
|  | 				} | |||
|  | 				let transfrom = '' | |||
|  | 				for (let i in styles) { | |||
|  | 					let line = this.toLine(i) | |||
|  | 					transfrom += line + ':' + styles[i] + ';' | |||
|  | 				} | |||
|  | 				return transfrom | |||
|  | 			} | |||
|  | 		}, | |||
|  | 		created() { | |||
|  | 			// this.timer = null
 | |||
|  | 			// this.nextTick = (time = 50) => new Promise(resolve => {
 | |||
|  | 			// 	clearTimeout(this.timer)
 | |||
|  | 			// 	this.timer = setTimeout(resolve, time)
 | |||
|  | 			// 	return this.timer
 | |||
|  | 			// });
 | |||
|  | 		}, | |||
|  | 		methods: { | |||
|  | 			change() { | |||
|  | 				this.$emit('click', { | |||
|  | 					detail: this.isShow | |||
|  | 				}) | |||
|  | 			}, | |||
|  | 			open() { | |||
|  | 				clearTimeout(this.timer) | |||
|  | 				this.isShow = true | |||
|  | 				this.transform = '' | |||
|  | 				this.ani.in = '' | |||
|  | 				for (let i in this.getTranfrom(false)) { | |||
|  | 					if (i === 'opacity') { | |||
|  | 						this.ani.in = 'fade-in' | |||
|  | 					} else { | |||
|  | 						this.transform += `${this.getTranfrom(false)[i]} ` | |||
|  | 					} | |||
|  | 				} | |||
|  | 				this.$nextTick(() => { | |||
|  | 					setTimeout(() => { | |||
|  | 						this._animation(true) | |||
|  | 					}, 50) | |||
|  | 				}) | |||
|  | 
 | |||
|  | 			}, | |||
|  | 			close(type) { | |||
|  | 				clearTimeout(this.timer) | |||
|  | 				this._animation(false) | |||
|  | 			}, | |||
|  | 			_animation(type) { | |||
|  | 				let styles = this.getTranfrom(type) | |||
|  | 				// #ifdef APP-NVUE
 | |||
|  | 				if(!this.$refs['ani']) return | |||
|  | 				animation.transition(this.$refs['ani'].ref, { | |||
|  | 					styles, | |||
|  | 					duration: this.duration, //ms
 | |||
|  | 					timingFunction: 'ease', | |||
|  | 					needLayout: false, | |||
|  | 					delay: 0 //ms
 | |||
|  | 				}, () => { | |||
|  | 					if (!type) { | |||
|  | 						this.isShow = false | |||
|  | 					} | |||
|  | 					this.$emit('change', { | |||
|  | 						detail: this.isShow | |||
|  | 					}) | |||
|  | 				}) | |||
|  | 				// #endif
 | |||
|  | 				// #ifndef APP-NVUE
 | |||
|  | 				this.transform = '' | |||
|  | 				for (let i in styles) { | |||
|  | 					if (i === 'opacity') { | |||
|  | 						this.ani.in = `fade-${type?'out':'in'}` | |||
|  | 					} else { | |||
|  | 						this.transform += `${styles[i]} ` | |||
|  | 					} | |||
|  | 				} | |||
|  | 				this.timer = setTimeout(() => { | |||
|  | 					if (!type) { | |||
|  | 						this.isShow = false | |||
|  | 					} | |||
|  | 					this.$emit('change', { | |||
|  | 						detail: this.isShow | |||
|  | 					}) | |||
|  | 
 | |||
|  | 				}, this.duration) | |||
|  | 				// #endif
 | |||
|  | 
 | |||
|  | 			}, | |||
|  | 			getTranfrom(type) { | |||
|  | 				let styles = { | |||
|  | 					transform: '' | |||
|  | 				} | |||
|  | 				this.modeClass.forEach((mode) => { | |||
|  | 					switch (mode) { | |||
|  | 						case 'fade': | |||
|  | 							styles.opacity = type ? 1 : 0 | |||
|  | 							break; | |||
|  | 						case 'slide-top': | |||
|  | 							styles.transform += `translateY(${type?'0':'-100%'}) ` | |||
|  | 							break; | |||
|  | 						case 'slide-right': | |||
|  | 							styles.transform += `translateX(${type?'0':'100%'}) ` | |||
|  | 							break; | |||
|  | 						case 'slide-bottom': | |||
|  | 							styles.transform += `translateY(${type?'0':'100%'}) ` | |||
|  | 							break; | |||
|  | 						case 'slide-left': | |||
|  | 							styles.transform += `translateX(${type?'0':'-100%'}) ` | |||
|  | 							break; | |||
|  | 						case 'zoom-in': | |||
|  | 							styles.transform += `scale(${type?1:0.8}) ` | |||
|  | 							break; | |||
|  | 						case 'zoom-out': | |||
|  | 							styles.transform += `scale(${type?1:1.2}) ` | |||
|  | 							break; | |||
|  | 					} | |||
|  | 				}) | |||
|  | 				return styles | |||
|  | 			}, | |||
|  | 			_modeClassArr(type) { | |||
|  | 				let mode = this.modeClass | |||
|  | 				if (typeof(mode) !== "string") { | |||
|  | 					let modestr = '' | |||
|  | 					mode.forEach((item) => { | |||
|  | 						modestr += (item + '-' + type + ',') | |||
|  | 					}) | |||
|  | 					return modestr.substr(0, modestr.length - 1) | |||
|  | 				} else { | |||
|  | 					return mode + '-' + type | |||
|  | 				} | |||
|  | 			}, | |||
|  | 			// getEl(el) {
 | |||
|  | 			// 	console.log(el || el.ref || null);
 | |||
|  | 			// 	return el || el.ref || null
 | |||
|  | 			// },
 | |||
|  | 			toLine(name) { | |||
|  | 				return name.replace(/([A-Z])/g, "-$1").toLowerCase(); | |||
|  | 			} | |||
|  | 		} | |||
|  | 	} | |||
|  | </script> | |||
|  | 
 | |||
|  | <style> | |||
|  | 	.uni-transition { | |||
|  | 		transition-timing-function: ease; | |||
|  | 		transition-duration: 0.3s; | |||
|  | 		transition-property: transform, opacity; | |||
|  | 	} | |||
|  | 
 | |||
|  | 	.fade-in { | |||
|  | 		opacity: 0; | |||
|  | 	} | |||
|  | 
 | |||
|  | 	.fade-active { | |||
|  | 		opacity: 1; | |||
|  | 	} | |||
|  | 
 | |||
|  | 	.slide-top-in { | |||
|  | 		/* transition-property: transform, opacity; */ | |||
|  | 		transform: translateY(-100%); | |||
|  | 	} | |||
|  | 
 | |||
|  | 	.slide-top-active { | |||
|  | 		transform: translateY(0); | |||
|  | 		/* opacity: 1; */ | |||
|  | 	} | |||
|  | 
 | |||
|  | 	.slide-right-in { | |||
|  | 		transform: translateX(100%); | |||
|  | 	} | |||
|  | 
 | |||
|  | 	.slide-right-active { | |||
|  | 		transform: translateX(0); | |||
|  | 	} | |||
|  | 
 | |||
|  | 	.slide-bottom-in { | |||
|  | 		transform: translateY(100%); | |||
|  | 	} | |||
|  | 
 | |||
|  | 	.slide-bottom-active { | |||
|  | 		transform: translateY(0); | |||
|  | 	} | |||
|  | 
 | |||
|  | 	.slide-left-in { | |||
|  | 		transform: translateX(-100%); | |||
|  | 	} | |||
|  | 
 | |||
|  | 	.slide-left-active { | |||
|  | 		transform: translateX(0); | |||
|  | 		opacity: 1; | |||
|  | 	} | |||
|  | 
 | |||
|  | 	.zoom-in-in { | |||
|  | 		transform: scale(0.8); | |||
|  | 	} | |||
|  | 
 | |||
|  | 	.zoom-out-active { | |||
|  | 		transform: scale(1); | |||
|  | 	} | |||
|  | 
 | |||
|  | 	.zoom-out-in { | |||
|  | 		transform: scale(1.2); | |||
|  | 	} | |||
|  | </style> |