实现 Vue 折叠面板组件

  • 实现 Vue 折叠面板组件已关闭评论
  • 99 次浏览
  • A+
所属分类:Web前端
摘要

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


block 和 none 问题

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

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

JS 辅助实现

这个时候就需要借助 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> 

setup

通过一个变量 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`; }); 

CSS 动画

.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); } 

实现效果

实现 Vue 折叠面板组件