1,组件
该组件 collapse-transition.vue 是内部组件,设计给 Collapse 折叠面板 使用的,实现了高度变化的折叠动画。具体分析可以看我写的 这篇文章
不过经过改造可在其他Vue项目引入使用(删除 element-plus 相关的依赖配置)。改造后的代码如下:
<template>
<transition name="collapse-transition" v-on="on">
<slot />
</transition>
</template>
<script setup>
// https://cn.vuejs.org/guide/built-ins/transition.html#javascript-hooks
const on = {
// el 是被 transition 包裹的元素
beforeEnter(el) {
if (!el.dataset) el.dataset = {}
// padding 会占据高度,如果一开始高度为0,而 padding 不为0,则在动画开始瞬间元素的显示高度是上下padding,不是从0开始的
el.dataset.oldPaddingTop = el.style.paddingTop
el.dataset.oldPaddingBottom = el.style.paddingBottom
el.style.maxHeight = 0
el.style.paddingTop = 0
el.style.paddingBottom = 0
},
enter(el) {
el.dataset.oldOverflow = el.style.overflow
if (el.scrollHeight !== 0) {
el.style.maxHeight = `${el.scrollHeight}px`
el.style.paddingTop = el.dataset.oldPaddingTop
el.style.paddingBottom = el.dataset.oldPaddingBottom
} else {
el.style.maxHeight = 0
el.style.paddingTop = el.dataset.oldPaddingTop
el.style.paddingBottom = el.dataset.oldPaddingBottom
}
el.style.overflow = 'hidden'
},
afterEnter(el) {
el.style.maxHeight = ''
el.style.overflow = el.dataset.oldOverflow
},
beforeLeave(el) {
if (!el.dataset) el.dataset = {}
el.dataset.oldPaddingTop = el.style.paddingTop
el.dataset.oldPaddingBottom = el.style.paddingBottom
el.dataset.oldOverflow = el.style.overflow
el.style.maxHeight = `${el.scrollHeight}px`
el.style.overflow = 'hidden'
},
leave(el) {
if (el.scrollHeight !== 0) {
el.style.maxHeight = 0
el.style.paddingTop = 0
el.style.paddingBottom = 0
}
},
afterLeave(el) {
el.style.maxHeight = ''
el.style.overflow = el.dataset.oldOverflow
el.style.paddingTop = el.dataset.oldPaddingTop
el.style.paddingBottom = el.dataset.oldPaddingBottom
},
}
</script>
<style>
.collapse-transition-leave-active,
.collapse-transition-enter-active {
transition: 0.3s max-height ease-in-out,
0.3s padding-top ease-in-out,
0.3s padding-bottom ease-in-out;
}
</style>
2,使用
<script setup>
import { ref } from "vue";
import CollapseTransition from "./components/collapse-transition.vue";
const visible = ref(false);
</script>
<template>
<button @click="visible = !visible">切换</button>
<CollapseTransition>
<ul v-if="visible" class="box">
<li v-for="n in 10" class="item">{{ n }}</li>
</ul>
</CollapseTransition>
</template>
<style>
.box {
border: 1px solid red;
}
.item {
background-color: bisque;
margin-bottom: 10px;
}
</style>
效果展示
3,遇到的问题
注意到使用了 transition
组件,并给被包裹的元素 box 添加内联样式,来实现的过渡动画。
并且该组件的特点:无论元素 box 的scrollHeight
有多高,都会完美实现height:0 --> scrollHeight
的折叠动画。
问题来了,
如果想限制展开的高度,比如 box 的可视高度150px,超出滚动。该如何实现?
解决
只要在 box 外增加一层 wrap,限制高度即可。
<template>
<CollapseTransition>
<div v-if="visible" class="wrap">
<ul class="box">
<li v-for="n in 10" class="item">{{ n }}</li>
</ul>
</div>
</CollapseTransition>
</template>
<style>
.wrap {
height: 150px;
overflow: auto;
}
/* ... */
</style>
效果展示
以上。