一、css transition實現動畫效果
在Vue中實現展開收起動畫的常用方式就是使用css transition。使用transition可以給目標元素的任意狀態變化提供動畫效果,比如在元素高度從0到高度自適應的過程中播放動畫。
下面是一個基本的例子,其中<transition>元素用於包裹需要動畫效果的元素,然後可以通過指定name屬性和定義對應狀態的css樣式來實現動畫:
<template>
<div>
<button @click="isVisible = !isVisible">Toggle</button>
<transition name="slide">
<div v-if="isVisible">Some content here...</div>
</transition>
</div>
</template>
<style>
.slide-enter-active,
.slide-leave-active {
transition: all 0.3s ease;
}
.slide-enter,
.slide-leave-to {
opacity: 0;
transform: translateY(100%);
}
</style>
<script>
export default {
data() {
return {
isVisible: false
};
}
};
</script>
二、使用第三方Vue庫
雖然使用css transition可以實現基本的展開收起動畫效果,但是在實現自定義複雜動畫效果時就會比較困難。此時可以使用一些第三方Vue組件庫,比如Vue的官方動畫庫vue-transition,還有比較流行的動畫庫animate.css。
下面以animate.css為例,介紹如何使用第三方庫實現動畫效果。
首先安裝animate.css:
npm install animate.css -S
然後在需要使用動畫效果的組件中引入該庫:
import 'animate.css';
下面是一個使用animate.css實現展開收起動畫的例子:
<template>
<div>
<button @click="isVisible = !isVisible">Toggle</button>
<div class="container" :class="{ 'animate__animated': isVisible, 'animate__fadeIn': isVisible, 'animate__fadeOut': !isVisible }">
<div class="content" v-if="isVisible">Some content here...</div>
</div>
</div>
</template>
<style>
.container {
display: flex;
justify-content: center;
}
.content {
width: 50%;
padding: 20px;
}
</style>
<script>
export default {
data() {
return {
isVisible: false
};
}
};
</script>
三、使用JS方法手動實現動畫
如果對於css transition和第三方庫都不夠熟悉或者不想使用第三方庫,那麼可以通過JS手動實現動畫效果。手動實現動畫主要利用Vue提供的以下API:
- <transition>的鉤子函數
- Vue的$refs屬性
下面是一個手動實現展開收起動畫的例子。需要注意的是,這個例子只是為了演示手動動畫實現的原理,不是一個完整的方案,需要自己根據實際需求進行完善。
<template>
<div>
<button @click="toggle">Toggle</button>
<div ref="content" class="content" :style="{ height: height + 'px' }">Some content here...</div>
</div>
</template>
<style>
.content {
transition: height 0.3s ease;
overflow: hidden;
}
</style>
<script>
export default {
data() {
return {
height: 0
};
},
methods: {
toggle() {
if (this.height === 0) {
this.height = this.$refs.content.scrollHeight;
} else {
this.height = 0;
}
}
}
};
</script>
四、應用場景舉例
展開收起動畫在實際應用中有很多場景,比如:
- 在商品列表中,點擊商品標題可以展開該商品的詳細信息:
<template>
<div v-for="item in productList">
<div class="title" @click="toggle(item)">{{ item.title }}</div>
<transition name="slide">
<div class="detail" :class="{ 'isActive': item.isActive }" v-if="item.isActive">{{ item.detail }}</div>
</transition>
</div>
</template>
<style>
.slide-enter-active,
.slide-leave-active {
transition: all 0.3s ease;
}
.slide-enter,
.slide-leave-to {
opacity: 0;
transform: translateY(100%);
}
.title {
cursor: pointer;
}
.detail {
padding: 10px;
border: 1px solid black;
margin-top: 10px;
display: none;
}
.isActive {
display: block;
}
</style>
<script>
export default {
data() {
return {
productList: [
{ title: 'Product 1', detail: 'Details of product 1', isActive: false },
{ title: 'Product 2', detail: 'Details of product 2', isActive: false },
{ title: 'Product 3', detail: 'Details of product 3', isActive: false }
]
};
},
methods: {
toggle(item) {
item.isActive = !item.isActive;
}
}
};
</script>
<template>
<div v-for="comment in commentList">
<div class="comment">{{ comment.content }}</div>
<div class="reply" @click="toggle(comment)" v-if="comment.hasReply">{{ comment.numOfReply }} replies</div>
<transition name="slide">
<div class="reply-list" :class="{ 'isActive': comment.isActive }" v-if="comment.isActive">
<div v-for="reply in comment.replyList" class="reply">{{ reply.content }}</div>
</div>
</transition>
</div>
</template>
<style>
.slide-enter-active,
.slide-leave-active {
transition: all 0.3s ease;
}
.slide-enter,
.slide-leave-to {
opacity: 0;
transform: translateY(100%);
}
.reply {
cursor: pointer;
margin-top: 10px;
}
.reply-list {
padding: 10px;
border: 1px solid black;
margin-top: 10px;
display: none;
}
.isActive {
display: block;
}
</style>
<script>
export default {
data() {
return {
commentList: [
{ content: 'Comment 1', hasReply: true, numOfReply: 2, replyList: [ { content: 'Reply 1.1' }, { content: 'Reply 1.2' } ], isActive: false },
{ content: 'Comment 2', hasReply: false },
{ content: 'Comment 3', hasReply: true, numOfReply: 1, replyList: [ { content: 'Reply 3.1' } ], isActive: false },
]
};
},
methods: {
toggle(comment) {
comment.isActive = !comment.isActive;
}
}
};
</script>
原創文章,作者:小藍,如若轉載,請註明出處:https://www.506064.com/zh-hk/n/236887.html