mirror of
				https://github.com/YunaiV/ruoyi-vue-pro.git
				synced 2025-10-31 10:37:41 +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>
 | 
