实现 Vue 折叠面板组件

网站建设5年前发布
60 0 0
文章目录

一些 CSS 属性可以是动画的,也就是说,当它的值改变时,它可以以平滑的方式改变。

做折叠面板最简单的方式是改变它的 blocknone,这两个属性值不包含在可动画属性中。详见:。所以,设置 CSS 动画(keyframes)或 transition 都是没有效果的。

这个时候就需要借助 JS 来实现折叠面板。首先,获取折叠面板内容的高度,有了高度按照一定周期来逐步增加高度,或逐步减少高度。

<div class="l-expandable">
 <div class="l-expandable__title">
 <div @click="isToggled = !isToggled">
 <div>
 <slot name="icon" />
 </div>
 {{ text }}
 </div>
 <div @click="toggle">
 <i-ep-arrow-down />
 </div>
 </div>
 <div
 @click="toggle"
 :class="{ 'arrow-up': !isToggled, 'arrow-down': isToggled }">
 <div class="arrow">
 <i-ep-arrow-down />
 </div>
 </div>
</div>

通过一个变量 isToggled 来判断是否折叠过面板。content 是获取面板内容的模板引用,height 是高度,对模板引用的高度进行设置。

// setup

const isToggled = ref(true);
const content = ref();
const height = ref();

// 把每一个折叠面板的高度都分成 10 份来间接性执行,执行完最后一帧之后设置 0,即不显示内容
function toggleClose() {
 let counter = 9;
 let cHeight = height.value;
 const interval = setInterval(() => {
 cHeight -= height.value / 10;
 content.value.style.height = `${cHeight.value}px`;
 counter--;
 if (counter == 0) {
 content.value.style.height = `${0}px`;
 // 已经折叠了面板
 isToggled.value = false;
 clearInterval(interval);
 }
 }, 10);
}

function toggleOpen() {
 let counter = 9;
 let cHeight = 0;
 const interval = setInterval(() => {
 cHeight += height.value / 10;
 content.value.style.height = `${cHeight}px`;
 counter--;
 if (counter == 0) {
 content.value.style.height = `${height.value}px`;
 // 已经打开了面板
 isToggled.value = true;
 clearInterval(interval);
 }
 }, 10);
}

function toggle() {
 if (isToggled.value) {
 toggleClose();
 } else {
 toggleOpen();
 }
}

// 组件内容渲染完成之后,获取模板引用对象,计算高度,并插入到 CSS 样式中
onMounted(() => {
 height.value = $(content.value).height();
 content.value.style.height = `${height.value}px`;
});

.l-expandable__title {
 border-left: 4px solid var(--el-color-primary);
}

.arrow {
 transform: scale(0, 0);
}

.l-expandable__title:hover .arrow {
 transform: scale(1, 1);
}

.arrow-up {
 animation: arrow-up-animation 0.3s ease-in;
 transform: rotate(180deg);
}

.arrow-down {
 animation: arrow-down-animation 0.3s ease-in;
 transform: rotate(0deg);
}

@keyframes arrow-up-animation {
 @for $index from 0 to 10 {
 #{$index * 10%} {
 transform: rotate($index * 18deg);
 }
 }
}

@keyframes arrow-down-animation {
 @for $index from 0 to 10 {
 #{$index * 10%} {
 transform: rotate(180deg - $index * 18deg);
 }
 }
}

.l-expandable__content {
 overflow: hidden;
 transition: var(--l-transition);
}

© 版权声明

相关文章