zoukankan      html  css  js  c++  java
  • vue2.0 transition -- demo实践填坑

    前言

    vue1.0版本和2.0版本的过渡系统改变还是蛮彻底的,具体请自行详看文档介绍:https://vuefe.cn/v2/guide/migration.html#过渡。在使用2.0版本做过渡效果的时候,虽然比1.0版本强大很多,但是实践过程中还是踩了一些不应该踩但是还是踩了的坑。虽然官网文档已经很详细地介绍了各种应用场景,但是这里还是通过几个小demo案例来感受下vue2.0 transition 带来的便利吧!

    实践

    这里将通过四个实践小案例来体验和学习css过渡,css动画,javascript钩子,列表过渡的应用。至于案例用到的知识点就请自行学习官网文档。
    css过渡--实践
    先来看看demo效果:
    css过滤

    这个案例其实很简单,通过一个transition来触发多个子元素的过渡效果,我们只需要定义元素对应的过渡效果就可以,其他事情vue会帮我们搞定,由此可以扩展出其他酷炫的过渡场景效果。先来看看这个简单案例的代码实现:

    <template>
    	<div class="app">
    		<button @click="showMenu" class="btn">{{text}}</button>
    		<transition name="move">
    			<div class="menu" v-show="show">
    				<div class="inner inner-1">1</div>
    				<div class="inner inner-2">2</div>
    				<div class="inner inner-3">3</div>
    			</div>
    		</transition>
    	</div>
    </template>
    
    <script type="text/ecmascript-6">
    	export default {
    		data () {
    			return {
    				show: false
    			};
    		},
    		methods: {
    			showMenu () {
    				this.show = !this.show;
    			}
    		},
    		computed: {
    			text () {
    				return this.show ? '收' : '开';
    			}
    		}
    	};
    </script>
    
    <style lang="stylus" rel="stylesheet/stylus">
    	.app
    		.btn
    			position: fixed
    			bottom: 50px
    			right: 10px
    			z-index: 10
    			 50px
    			height: 50px
    			line-height: 50px
    			border-radius: 50%
    			border: none
    			outline: none
    			color: #fff
    			font-size: 18px
    			background: blue
    		.menu
    			position: fixed
    			bottom: 50px
    			right: 10px
    			 50px
    			height: 50px
    			border-radius: 50%
    			transition: all .7s ease-in
    			&.move-enter-active
    				.inner
    					transform: translate3d(0, 0, 0)
    					transition-timing-function: cubic-bezier(0, .57, .44, 1.97)
    				.inner-1
    					transition-delay: .1s
    				.inner-2
    					transition-delay: .2s
    				.inner-3
    					transition-delay: .3s
    			&.move-enter, &.move-leave-active
    				.inner
    					transition-timing-function: ease-in-out
    				.inner-1
    					transform: translate3d(0, 60px, 0)
    					transition-delay: .3s
    				.inner-2
    					transform: translate3d(40px, 40px, 0)
    					transition-delay: .2s
    				.inner-3
    					transform: translate3d(60px, 0, 0)
    					transition-delay: .1s
    			.inner
    				display: inline-block
    				position: absolute
    				 30px
    				height: 30px
    				line-height: 30px
    				border-radius: 50%
    				background: red
    				text-align: center
    				color: #fff
    				transition: all .4s
    			.inner-1
    				top: -50px
    				left: 10px
    			.inner-2
    				left: -30px
    				top: -30px
    			.inner-3
    				left: -50px
    				top: 10px
    </style>
    

    可以看到我们的代码基本主要是完成css过渡效果的样式,而触发过渡效果只是简单地通过一个click事件就搞定了,vue会自动嗅探目标元素是否有 CSS 过渡或动画,并在合适时添加/删除 CSS 类名。那下一个demo就来简单实现一下使用css animation 做过渡的效果。

    css 动画--实践
    先来看看demo效果:

    css动画

    这个案例其实跟上面的demo差不多,不同之处在于过渡效果是使用css动画来实现,看下实现的代码:

    <template>
    	<div class="app">
    	<button @click="showball" class="btn">show</button>
    		<transition name="move" type="animation">
    			<div class="ball" v-show="show">
    				<div class="inner"></div>
    			</div>
    		</transition>
    	</div>
    </template>
    
    <script type="text/ecmascript-6">
    	export default {
    		data () {
    			return {
    				show: false
    			};
    		},
    		methods: {
    			showball () {
    				this.show = !this.show;
    			}
    		}
    	};
    </script>
    
    <style lang="stylus" rel="stylesheet/stylus">
    	@keyframes shape-change {
    		0%, 100% {
    			border-radius: 50%
    			background: red
    		}
    		50% {
    			border-radius: 0
    			background: blue
    		}
    	}
    	
    	@keyframes moveball-in {
    		0% {
    			transform: translate3d(300px,-200px,0)
    		}
    		50% {
    			transform: translate3d(100px,-400px,0)
    		}
    		100% {
    			transform: translate3d(0,0,0)
    		}
    	}
    	@keyframes moveball-out {
    		0% {
    			transform: translate3d(0,0,0)
    		}
    		50% {
    			transform: translate3d(100px,-400px,0)
    		}
    		100% {
    			transform: translate3d(300px,-200px,0)
    		}
    	}
    	.app
    		.btn
    			 40px
    			height: 30px
    			margin-top: 40px
    			border: none
    			outline: none
    			background: red
    			color: #fff
    		.ball
    			position: absolute
    			bottom: 20px
    			left: 20px
    			 50px
    			height: 50px
    			transition: all 1s cubic-bezier(.22,-0.86,.97,.58)
    			&.move-enter-active
    				opacity: 1
    				animation: moveball-in 1s
    				.inner
    					animation: shape-change 1s
    			&.move-leave-active
    				opacity: 0.8
    				animation: moveball-out 1s
    				.inner
    					animation: shape-change 1s
    			.inner
    				display: inline-block
    				 30px
    				height: 30px
    				border-radius: 50%
    				background: red
    				transition: all 1s linear
    </style>
    

    从css代码可以看出,我们只是在vue过渡类名下加了不同的animation而已。官网文档明确说明当只使用transition或animation其中一种时,vue是能自动监听对应的类型的,但是如果同一个元素同时使用两种效果,就需要明确指定监听哪一种类型,不过官网并没有给出具体的栗子。那其实这个demo已经简单地实现同时使用两种类型的情况,可以看到有一个透明度的变化。但是假如animation里使用了transform,并且外面也使用了transform的话,那么元素在过渡的时候动画效果就会有冲突,效果就有点出入了。

    JavaScript钩子 -- 实践
    前两个栗子都是有进入和离开的过渡,但是如果一些场景只需要进入过渡然后就结束了,那么这时就可以使用JavaScript钩子结合CSS transitions/animations来实现,当然也可以单独使用。看下demo:

    javascript钩子

    这个一个非常low的模拟炮弹发射的场景,可以看到小球有抛物线轨迹运动的过渡,而且发射出去就不会再回来了,那么这个demo就是使用了JavaScript钩子结合css来实现的,接下来看下关键代码:

    <template>
    	<div class="app">
    		<div class="gun" @click="launch($event)"></div>
    		<div class="shells-wrapper">
    		  <transition v-for="shell in shells" name="launch-shell" @before-enter="beforeEnter" @enter="enter" @after-enter="afterEnter">
    		    <div class="shell" v-show="shell.show">
    		      <div class="inner"></div>
    		    </div>
    		  </transition>
    		</div>
    		<div class="goal"></div>
    	</div>
    </template>
    

    首先,由于本身这个demo是一组元素的过渡,所以有些童鞋就会觉得用2.0提供的transition-group不就行了嘛。不过transition-group是列表过渡,我的理解是那一组元素是相关联的、互相影响的,但是这个demo的元素每个都是独立的,只不过是一组独立的元素过渡,所以还是用transition比较合理,那使用v-for就可以实现一组相同过渡的元素啦。接下来看JavaScript钩子怎么实现这个过渡:

    export default {
    		data () {
    			return {
    				shells: [
    					{
    						show: false
    					},
    					{
    						show: false
    					},
    					{
    						show: false
    					}
    				]
    			};
    		},
    		methods: {
    			launch (event) {
    				for (let i = 0; i < this.shells.length; i++) {
    				  let shell = this.shells[i];
    				  if (!shell.show) {
    				    shell.show = true;
    				    shell.target = event.target;
    				    return;
    				  }
    				}
    			},
    			beforeEnter (el) {
    				let count = this.shells.length;
    				while (count--) {
    					let shell = this.shells[count];
    					if (shell.show) {
    						let rect = shell.target.getBoundingClientRect();
    						let left = rect.left - 32;
    						let top = -(window.innerHeight - rect.top - 15);
    						el.style.display = '';
    						el.style.webkitTransform = `translate3d(0,${top}px,0)`;
    						el.style.transform = `translate3d(0,${top}px,0)`;
    						let inner = el.getElementsByClassName('inner')[0];
    						inner.style.webkitTransform = `translate3d(${left}px,0,0)`;
    						inner.style.transform = `translate3d(${left}px,0,0)`;
    					}
    				}
    			},
    			enter (el, done) {
    				/* eslint-disable no-unused-vars */
    				let refresh = el.offsetHeight;
    				this.$nextTick(() => {
    					el.style.webkitTransform = 'translate3d(0,0,0)';
    					el.style.transform = 'translate3d(0,0,0)';
    					let inner = el.getElementsByClassName('inner')[0];
    					inner.style.webkitTransform = 'translate3d(0,0,0)';
    					inner.style.transform = 'translate3d(0,0,0)';
    				});
    				done();
    			},
    			afterEnter (el) {
    				let ball = this.shells[0];
    				ball.show = false;
    				el.style.display = 'none';
    			}
    		}
    	};
    

    过渡元素就不需要为其添加vue的过渡css类名了,只需在元素本身添加transition即可,那vue在之前css过渡的时候会自动帮我们去添加对应的类名来完成过渡效果,但是用javascript钩子就需要我们自己完成这个始末状态的设置了。当我们点击触发一个过渡的时候,我们在beforeEnter里先拿到当前元素的偏移位置,然后给过渡元素设置其起始位置,在enter里需要重新触发下浏览器的重绘,然后在下一帧重新设置元素的结束位置,这时就会产生过渡效果,在过渡完成后我们将当前元素隐藏即可。那刚才讲到的列表过渡,接下来就是关于使用transition-group的一个小demo了。

    transition-group -- 实践
    先看下demo效果:

    transition-group.gif

    其实就是个简单的todo lists的小demo,可以看到,当其中一个元素过渡的时候,会影响其他元素的过渡。当然,删除按钮其实本身也是一个transition过渡,也就是说可以在transition-group里使用transition,看下相关代码:

    <template>
    	<div class="app">
    		<button @click="add" class="add-btn">+</button>
    		<transition-group name="slide" tag="ul" class="list-wrapper">
    			<li class="list" v-for="(item, index) in lists" v-touch:swipeleft="showBtn.bind(this, index)" v-touch:swiperight="hideBtn.bind(this, index)" :key="item">
    				<span class="text">{{item.text}}</span>
    				<transition name="move">
    					<button class="del-btn" @click="delList(index)" v-show="item.show">删除</button>
    				</transition>
    			</li>
    		</transition-group>
    	</div>
    </template>
    

    有个小坑的地方就是,之前看官网列表过渡的栗子,它是一个数组,元素都是数字,并且每一项都必须设置唯一的key值。所以我完成demo的时候就自作聪明地将索引值传给key,结果过渡老是不对,后来换成对应的item就正常了(生无可恋脸)。这个demo用到了vue-touch,虽然github上说不支持2.0版本了,但是有一个next分支是支持的,只需在项目下安装它即可:

    sudo npm install --save git://github.com/vuejs/vue-touch.git#next
    

    这里看下主要的样式:

    .list
    	display: flex
    	 100%
    	height: 40px
    	line-height: 40px
    	margin-bottom: 10px
    	color: #666
    	font-size: 14px
    	background: #eee
    	transition: all .4s
    	&.slide-move
            transition: transform 1s
    	&.slide-enter
    		transform: translate3d(-100%, 0, 0)
    	&.slide-leave-active
    		position: absolute
    		transform: translate3d(-100%, 0, 0)
    	&:last-child
    		margin-bottom: 0
    	.del-btn
    		flex: 0 0 60px
    		border: none
    		outline: none
    		color: #fff
    		background: red
    		transition: all .4s
    		&.move-enter, &.move-leave-active
    			transform: translate3d(70px, 0, 0)
    	.text
    		flex: 1
    		padding-left: 20px
    

    如果改变定位过渡的duration与进入离开一样的话,其实可以不用-move,这里设置-move的过渡的duration不同于元素进入离开的duration产生一种速度差,看起来舒服点。而且-leave-active需要设置position: absolute才会有效果。现在看来其实列表过渡也是很容易实现的。

    最后

    其实vue2.0过渡系统还提供了其他场景的过渡应用,这里就不展开赘述了。引用官网文档的一句话:唯一的限制是你的想象力。哈哈...

    PS: 如需转载,请注明出处,谢谢!!!

  • 相关阅读:
    ASP+Access UTF-8 网页乱码问题解决办法
    使用PowerDesigner生成Access数据库
    crontab详解
    Pending Statistics
    Recovery with Incremental Backups
    ASP的Global.asa使用说明
    cocos基础教程(5)数据结构介绍之cocos2d::Map<K,V>
    cocos基础教程(5)数据结构介绍之cocos2d::Vector
    cocos基础教程(4)基础概念介绍
    cocos进阶教程(1)Lua调用自定义C++类和函数的最佳实践
  • 原文地址:https://www.cnblogs.com/jr1993/p/vue.html
Copyright © 2011-2022 走看看