文章目录
- 一些 CSS 属性可以是动画的,也就是说,当它的值改变时,它可以以平滑的方式改变。 做折叠面板最简单的方式是改变它的 block 或 none,这两个属性值不包含在可动画属性中。详见:。所以,设置 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); }
一些 CSS 属性可以是动画的,也就是说,当它的值改变时,它可以以平滑的方式改变。
做折叠面板最简单的方式是改变它的 block 或 none,这两个属性值不包含在可动画属性中。详见:。所以,设置 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);
}
.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);
}
© 版权声明
文章版权归作者所有,未经允许请勿转载。