Vue基础16
过度与动画
动画效果
App.vue
<template>
<div class="bg">
<button @click="isShow=!isShow">显示/隐藏</button>
<transition appear> <!-- appear意味着刷新完毕后会执行一遍进入动画-->
<h1 v-show="isShow">你好啊!</h1>
</transition>
<transition name="hello">
<h1 v-show="isShow">你好啊!</h1>
</transition>
</div>
</template>
<script>
export default {
name: "App",
data(){
return{
isShow:true
}
},
}
</script>
<style lang="less">
.bg{
height: 937px;
box-sizing: border-box;
}
h1{
background-color: orange;
}
h1:last-child{
background-color: skyblue;
}
//transition无名时候的进入动画
.v-enter-active{
animation: trans 2s linear;
}
//transition无名时候的离开动画
.v-leave-active{
animation: trans 2s linear reverse; //reverse 倒着播放动画
}
@keyframes trans {
from{
transform: translateX(-100%)
}to{
transform: translateX(0);
}
}
//hello的进入动画
.hello-enter-active{
animation: trans 5s linear;
}
//hello的离开动画
.hello-leave-active{
animation: trans 5s linear reverse; //reverse 倒着播放动画
}
</style>
过度效果
App.vue
<template>
<div class="bg">
<!-- <Animation></Animation>-->
<TransitionEffect></TransitionEffect>
</div>
</template>
<script>
import Animation from "@/components/Animation";
import TransitionEffect from "@/components/TransitionEffect";
export default {
name: "App",
components:{Animation,TransitionEffect}
}
</script>
<style lang="less">
.bg{
height: 937px;
box-sizing: border-box;
}
</style>
TransitionEffect.vue
<template>
<div>
<button @click="isShow=!isShow">显示/隐藏</button>
<transition name="hello" appear>
<h2 v-show="isShow">你好啊!</h2>
</transition>
</div>
</template>
<script>
export default {
name: "TransitionEffect",
data(){
return{
isShow:false
}
}
}
</script>
<style scoped>
h2{
background-color: pink;
/*transition: 2s linear;*/
}
/*详细的写法*/
/*!*进入的起点*!
.hello-enter{
transform: translateX(-100%);
}
!*进入的终点*!
.hello-enter-to{
transform: translateX(0);
}
!*离开的起点*!
.hello-leave{
transform: translateX(0);
}
!*离开的终点*!
.hello-leave-to{
transform: translateX(-100%);
}*/
/*合并写法*/
/*进入的起点,离开的终点*/
.hello-enter,.hello-leave-to{
transform: translateX(-100%);
}
/*进入的终点,离开的起点*/
.hello-enter-to,.hello-leave{
transform: translateX(0);
}
/*如果不在标签上写的话,就在这里写动画运动时长与速度*/
.hello-enter-active,.hello-leave-active{
transition: 2s linear;
}
</style>
多个元素过度
App.vue
<template>
<div class="bg">
<!-- <Animation></Animation>-->
<!-- <TransitionEffect></TransitionEffect>-->
<MoreTransition></MoreTransition>
</div>
</template>
<script>
import Animation from "@/components/Animation";
import TransitionEffect from "@/components/TransitionEffect";
import MoreTransition from "@/components/MoreTransition";
export default {
name: "App",
components:{MoreTransition, Animation,TransitionEffect}
}
</script>
<style lang="less">
.bg{
height: 937px;
box-sizing: border-box;
}
</style>
MoreTransition.vue
<template>
<div>
<button @click="isShow=!isShow">显示/隐藏</button>
<transition-group name="introduce">
<h1 v-show="isShow" key="1" class="hello">你好啊!</h1>
<h1 v-show="!isShow" key="2" class="name">张三</h1>
</transition-group>
</div>
</template>
<script>
export default {
name: "MoreTransition",
data(){
return{
isShow:true
}
}
}
</script>
<style scoped>
.hello{
background-color: orange;
}
.name{
background-color: pink;
}
/* 进入的起点,离开的终点 */
.introduce-enter,.introduce-leave-to{
transform: translateX(-100%);
}
/* 进入的终点,离开的起点 */
.introduce-enter-to,introduce-leave{
transform: translateX(0);
}
.introduce-enter-active,.introduce-leave-active{
transition: 2s linear;
}
</style>
集成第三方动画
安装
- 在 npm官网 中找animate.css动画库
- 安装animate.css
执行命令
npm install animate.css
- 引入第三方库
import ‘animate.css’
应用
App.vue
<template>
<div class="bg">
<!-- <Animation></Animation>-->
<!-- <TransitionEffect></TransitionEffect>-->
<!-- <MoreTransition></MoreTransition>-->
<ThirdAnimation></ThirdAnimation>
</div>
</template>
<script>
import Animation from "@/components/Animation";
import TransitionEffect from "@/components/TransitionEffect";
import MoreTransition from "@/components/MoreTransition";
import ThirdAnimation from "@/components/ThirdAnimation";
export default {
name: "App",
components:{ThirdAnimation, MoreTransition, Animation,TransitionEffect}
}
</script>
<style lang="less">
.bg{
height: 937px;
box-sizing: border-box;
}
</style>
ThirdAnimation.vue
<template>
<div>
<button @click="isShow=!isShow">显示/隐藏</button>
<transition
name="animate__animated animate__bounce"
enter-active-class="animate__heartBeat"
leave-active-class="animate__backOutDown"
appear>
<h1 v-show="isShow">你好啊~</h1>
</transition>
</div>
</template>
<script>
import 'animate.css'
export default {
name: "ThirdAnimation",
data(){
return{
isShow:true
}
}
}
</script>
<style scoped>
h1{
background-color: skyblue;
text-align: center;
}
</style>
总结:Vue封装的过度与动画
-
作用:在插入、更新或移除DOM元素时,在合适的时候给元素添加样式类名。
-
图示:
-
写法:
(1)准备好样式:- 元素进入的样式:
1.v-enter:进入的起点
2.v-enter-active:进入过程中
3.v-enter-to:进入的终点 - 元素离开的样式:
1.v-leave:离开的起点
2.v-leave-active:离开过程中
3.v-leave-to:离开的终点
- 元素进入的样式:
(2)使用<transition>包裹要过度的元素,并配置name属性:
<transition name="hello">
<h1 v-show="isShow">你好啊!</h1>
</transition>
(3)备注:若有多个元素需要过度,则需要使用:<transition-group>,且每个元素都要指定key值
TodoList-过度与动画
在清单被添加时与删除时候加上动画
使用@keyframs写动画
MyItem.vue
<template>
<transition name="todo" appear>
<li @dblclick="editItem(todo)">
<!-- <input type="checkbox" name="matter" id="" v-model="todo.done">-->
<input type="checkbox" name="matter" id="" @change="checkDone(todo.id)" :checked="todo.done">
<input type="text" ref="inputTitle" :value="todo.title" class="editIn" v-show="todo.isEdit" @blur="ensureEdit($event,todo)" @keyup.enter="ensureEdit($event,todo)">
<span class="todoTitle" v-show="!todo.isEdit">{{todo.title}}</span>
<button class="delete" @click="deleteItem(todo.id)">删除</button>
<button class="edit" @click="editItem(todo)">编辑</button>
</li>
</transition>
</template>
<script>
import pubsub from 'pubsub-js'
export default {
name: "MyItem",
props:['todo'],
methods:{
deleteItem(id){
//消息的发布
if(confirm('确认删除嘛?')) pubsub.publish("deleteTodo",id)
},
checkDone(id){
//触发公共组件的某个事件
this.$bus.$emit("checkTodo",id)
},
//编辑
editItem(todo){
if(!todo.hasOwnProperty("isEdit")){
this.$set(todo,'isEdit',true)
}else{
todo.isEdit=true
}
//由于代码是按顺序执行的,所以不会在执行完上面的代码之后就重新渲染页面
//继续向下执行,但此时的input框还是隐藏状态,隐藏状态是没办法获取焦点的,因此使用定时器来延迟获取焦点
// setTimeout(()=>{
// this.$refs.inputTitle.focus()
// })
this.$nextTick(function(){
this.$refs.inputTitle.focus()
})
},
//失去焦点确认编辑成功
ensureEdit(e,todo){
todo.isEdit=false
if(!e.target.value.trim()) return alert("输入的内容不得为空")
this.$bus.$emit("editTodo",todo.id,e.target.value)
}
}
}
</script>
<style scoped lang="less">
li{
//height: 35%;
//width: 96%;
display: block;
//background-color: pink;
margin: auto;
padding: 12px;
border-top: 1px solid rgba(87, 87, 87, 0.3);
//border-left: 1px solid rgba(87, 87, 87, 0.3);
//border-right: 1px solid rgba(87, 87, 87, 0.3);
box-sizing: border-box;
//border-collapse: collapse;
.editIn{
font-size: 16px;
border: 1px solid #ccc;
padding: 5px;
border-radius: 4px;
box-sizing: border-box;
}
.editIn:focus{
border-color: #66afe9;
box-shadow: inset 0 1px 1px rgb(0 0 0 / 8%), 0 0 8px rgb(102 175 233 / 60%);
outline: none;
}
.delete{
background-color: #d9534f;
float: right;
padding: 3px 10px;
color: white;
border: 1px solid #d43f3a;
border-radius: 5px;
cursor: pointer;
&:hover{
background-color: #c9302c;
border: 1px solid #ac2925;
}
}
.edit{
//background-color: #337ab7;
float: right;
padding: 3px 10px;
margin-right: 5px;
color: white;
border: 1px solid #4cae4c;
border-radius: 5px;
cursor: pointer;
&:hover{
border: 1px solid #398439;
//background-color: #286090;
background-color: #449d44;
border-color: #398439;
}
background-color: #5cb85c;
//border-color: #4cae4c;
}
&:hover{
background-color: rgba(0,0,0,0.1);
}
}
/*添加时候位移变化 */
/*//进入的起点,离开的终点
.todo-enter,.todo-leave-to{
transform: translateX(100%);
}
//进入的终点,离开的起点
.todo-enter-to,.todo-leave{
transform: translateX(0);
}
.todo-enter-active,.todo-leave-active{
transition: 1s linear;
}*/
//添加与删除时候透明度变化
.todo-enter-active{
animation: trans 1s linear;
}
.todo-leave-active{
animation: trans 1s linear reverse;
}
@keyframes trans {
from{
opacity: 0;
}
to{
opacity: 1;
}
}
</style>
使用.v-enter,.v-leave写动画
<template>
<transition name="todo" appear>
<li @dblclick="editItem(todo)">
<!-- <input type="checkbox" name="matter" id="" v-model="todo.done">-->
<input type="checkbox" name="matter" id="" @change="checkDone(todo.id)" :checked="todo.done">
<input type="text" ref="inputTitle" :value="todo.title" class="editIn" v-show="todo.isEdit" @blur="ensureEdit($event,todo)" @keyup.enter="ensureEdit($event,todo)">
<span class="todoTitle" v-show="!todo.isEdit">{{todo.title}}</span>
<button class="delete" @click="deleteItem(todo.id)">删除</button>
<button class="edit" @click="editItem(todo)">编辑</button>
</li>
</transition>
</template>
<script>
import pubsub from 'pubsub-js'
export default {
name: "MyItem",
props:['todo'],
methods:{
deleteItem(id){
//消息的发布
if(confirm('确认删除嘛?')) pubsub.publish("deleteTodo",id)
},
checkDone(id){
//触发公共组件的某个事件
this.$bus.$emit("checkTodo",id)
},
//编辑
editItem(todo){
if(!todo.hasOwnProperty("isEdit")){
this.$set(todo,'isEdit',true)
}else{
todo.isEdit=true
}
//由于代码是按顺序执行的,所以不会在执行完上面的代码之后就重新渲染页面
//继续向下执行,但此时的input框还是隐藏状态,隐藏状态是没办法获取焦点的,因此使用定时器来延迟获取焦点
// setTimeout(()=>{
// this.$refs.inputTitle.focus()
// })
this.$nextTick(function(){
this.$refs.inputTitle.focus()
})
},
//失去焦点确认编辑成功
ensureEdit(e,todo){
todo.isEdit=false
if(!e.target.value.trim()) return alert("输入的内容不得为空")
this.$bus.$emit("editTodo",todo.id,e.target.value)
}
}
}
</script>
<style scoped lang="less">
li{
//height: 35%;
//width: 96%;
display: block;
//background-color: pink;
margin: auto;
padding: 12px;
border-top: 1px solid rgba(87, 87, 87, 0.3);
//border-left: 1px solid rgba(87, 87, 87, 0.3);
//border-right: 1px solid rgba(87, 87, 87, 0.3);
box-sizing: border-box;
//border-collapse: collapse;
.editIn{
font-size: 16px;
border: 1px solid #ccc;
padding: 5px;
border-radius: 4px;
box-sizing: border-box;
}
.editIn:focus{
border-color: #66afe9;
box-shadow: inset 0 1px 1px rgb(0 0 0 / 8%), 0 0 8px rgb(102 175 233 / 60%);
outline: none;
}
.delete{
background-color: #d9534f;
float: right;
padding: 3px 10px;
color: white;
border: 1px solid #d43f3a;
border-radius: 5px;
cursor: pointer;
&:hover{
background-color: #c9302c;
border: 1px solid #ac2925;
}
}
.edit{
//background-color: #337ab7;
float: right;
padding: 3px 10px;
margin-right: 5px;
color: white;
border: 1px solid #4cae4c;
border-radius: 5px;
cursor: pointer;
&:hover{
border: 1px solid #398439;
//background-color: #286090;
background-color: #449d44;
border-color: #398439;
}
background-color: #5cb85c;
//border-color: #4cae4c;
}
&:hover{
background-color: rgba(0,0,0,0.1);
}
}
//添加时候位移变化
//进入的起点,离开的终点
.todo-enter,.todo-leave-to{
transform: translateX(100%);
}
//进入的终点,离开的起点
.todo-enter-to,.todo-leave{
transform: translateX(0);
}
.todo-enter-active,.todo-leave-active{
transition: 1s linear;
}
/*//添加与删除时候透明度变化
.todo-enter-active{
animation: trans 1s linear;
}
.todo-leave-active{
animation: trans 1s linear reverse;
}
@keyframes trans {
from{
opacity: 0;
}
to{
opacity: 1;
}
}*/
</style>
不在MyItem中加,在MyList中加动画
MyItem.vue
<template>
<!-- <transition>-->
<li @dblclick="editItem(todo)">
<!-- <input type="checkbox" name="matter" id="" v-model="todo.done">-->
<input type="checkbox" name="matter" id="" @change="checkDone(todo.id)" :checked="todo.done">
<input type="text" ref="inputTitle" :value="todo.title" class="editIn" v-show="todo.isEdit" @blur="ensureEdit($event,todo)" @keyup.enter="ensureEdit($event,todo)">
<span class="todoTitle" v-show="!todo.isEdit">{{todo.title}}</span>
<button class="delete" @click="deleteItem(todo.id)">删除</button>
<button class="edit" @click="editItem(todo)">编辑</button>
</li>
<!-- </transition>-->
</template>
<script>
import pubsub from 'pubsub-js'
export default {
name: "MyItem",
props:['todo'],
methods:{
deleteItem(id){
//消息的发布
if(confirm('确认删除嘛?')) pubsub.publish("deleteTodo",id)
},
checkDone(id){
//触发公共组件的某个事件
this.$bus.$emit("checkTodo",id)
},
//编辑
editItem(todo){
if(!todo.hasOwnProperty("isEdit")){
this.$set(todo,'isEdit',true)
}else{
todo.isEdit=true
}
//由于代码是按顺序执行的,所以不会在执行完上面的代码之后就重新渲染页面
//继续向下执行,但此时的input框还是隐藏状态,隐藏状态是没办法获取焦点的,因此使用定时器来延迟获取焦点
// setTimeout(()=>{
// this.$refs.inputTitle.focus()
// })
this.$nextTick(function(){
this.$refs.inputTitle.focus()
})
},
//失去焦点确认编辑成功
ensureEdit(e,todo){
todo.isEdit=false
if(!e.target.value.trim()) return alert("输入的内容不得为空")
this.$bus.$emit("editTodo",todo.id,e.target.value)
}
}
}
</script>
<style scoped lang="less">
li{
//height: 35%;
//width: 96%;
display: block;
//background-color: pink;
margin: auto;
padding: 12px;
border-top: 1px solid rgba(87, 87, 87, 0.3);
//border-left: 1px solid rgba(87, 87, 87, 0.3);
//border-right: 1px solid rgba(87, 87, 87, 0.3);
box-sizing: border-box;
//border-collapse: collapse;
.editIn{
font-size: 16px;
border: 1px solid #ccc;
padding: 5px;
border-radius: 4px;
box-sizing: border-box;
}
.editIn:focus{
border-color: #66afe9;
box-shadow: inset 0 1px 1px rgb(0 0 0 / 8%), 0 0 8px rgb(102 175 233 / 60%);
outline: none;
}
.delete{
background-color: #d9534f;
float: right;
padding: 3px 10px;
color: white;
border: 1px solid #d43f3a;
border-radius: 5px;
cursor: pointer;
&:hover{
background-color: #c9302c;
border: 1px solid #ac2925;
}
}
.edit{
//background-color: #337ab7;
float: right;
padding: 3px 10px;
margin-right: 5px;
color: white;
border: 1px solid #4cae4c;
border-radius: 5px;
cursor: pointer;
&:hover{
border: 1px solid #398439;
//background-color: #286090;
background-color: #449d44;
border-color: #398439;
}
background-color: #5cb85c;
//border-color: #4cae4c;
}
&:hover{
background-color: rgba(0,0,0,0.1);
}
}
/*
//添加时候位移变化
//进入的起点,离开的终点
.todo-enter,.todo-leave-to{
transform: translateX(100%);
}
//进入的终点,离开的起点
.todo-enter-to,.todo-leave{
transform: translateX(0);
}
.todo-enter-active,.todo-leave-active{
transition: 1s linear;
}
*/
/*//添加与删除时候透明度变化
.todo-enter-active{
animation: trans 1s linear;
}
.todo-leave-active{
animation: trans 1s linear reverse;
}
@keyframes trans {
from{
opacity: 0;
}
to{
opacity: 1;
}
}*/
</style>
MyList.vue
<template>
<div>
<ul>
<div class="con">
<transition-group name="todo" appear>
<MyItem v-for="todo in todos" :todo="todo" :key="todo.id"/>
</transition-group>
</div>
</ul>
</div>
</template>
<script>
import MyItem from "@/components/MyItem";
export default {
name:'MyList',
components:{MyItem},
props:['todos']
}
</script>
<style scoped lang="less">
ul{
.con{
//width: 95%;
//margin: auto;
border-bottom: 1px solid rgba(87, 87, 87, 0.3);
border-left: 1px solid rgba(87, 87, 87, 0.3);
border-right: 1px solid rgba(87, 87, 87, 0.3);
margin: 0px 8px;
//background-color: pink;
}
}
//添加与删除时候透明度变化
.todo-enter-active{
animation: trans 1s linear;
}
.todo-leave-active{
animation: trans 1s linear reverse;
}
@keyframes trans {
from{
opacity: 0;
}
to{
opacity: 1;
}
}
</style>