You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							279 lines
						
					
					
						
							5.7 KiB
						
					
					
				
			
		
		
		
			
			
			
				
					
				
				
					
				
			
		
		
	
	
							279 lines
						
					
					
						
							5.7 KiB
						
					
					
				
								<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 {}
							 | 
						|
												}
							 | 
						|
											}
							 | 
						|
										},
							 | 
						|
										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,
							 | 
						|
													'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>
							 |