【推拉框-手风琴】vue3实现手风琴效果的组件

简言

在工作时有时会用到竖形手风琴效果的组件。
在此记录下实现代码和实现思路。

手风琴实现

结构搭建

搭建结构主要实现盒子间的排列效果。

  • 用flex布局或者其他布局方式将内容在一行排列
  • 把每一项的内容和项头用盒子包裹, 内容就是这一项要展示的内容(content-box),项头就是可以点击显示这一项的盒子(title-box)。
  • 默认第一项的context-box显示,即有宽度,其他项的content-box宽度为0.
  • content-box加上过渡样式,这样就会有推拉的感觉。
  • 由于是vue组件,那我们可以给它加上插槽,让组件可以自定义显示内容

在这里插入图片描述

功能搭建

  • 点击项头显示 点击项的内容区域。由于我们已经将未显示的content-box宽度设为0,所以只需要添加一个变量将带有宽度的类样式赋给当前点击项即可显示。
  • 宽度变化时,里面的内容样式可能会发生改动,所以我们需要给内容里的box加一个透明度的过渡效果,避免样式发生改变试被看到。
  • 加插槽,插槽点随意,合理就行。
  • 加属性,例如,当前显示项、当前显示项内容等。

代码

<template>
  <div class="accordion">
    <slot>
      <div class="item__box" v-for="(item, i) of list" :key="i">
        <div
          class="item__content"
          :class="[`item__content${i}`, { 'item__content-active': activeIndex === i }]"
        >
          <div class="item__content__detail">
            <slot :name="`item__content${i}`"> </slot>
          </div>
        </div>
        <div
          class="item__title"
          :class="[`item__title${i}`, { 'item__title-active': activeIndex === i }]"
        >
          <div class="item__title__detail" @click="() => tabChange(i)">
            <slot :name="`item__title${i}`">
              <img
                v-if="!!item.icon"
                :src="activeIndex === i ? getImageUrl(item.activeIcon  as string) : getImageUrl(item.icon)"
                alt=""
              />
              <div class="item__title__detail__text">{{ item.title }}</div>
            </slot>
          </div>
        </div>
      </div>
    </slot>
  </div>
</template>
<script lang="ts" setup>
import { reactive, toRefs, onBeforeMount, onMounted, ref } from 'vue'
import { getImageUrl } from '@/untils/index'

interface Item {
  icon?: string
  activeIcon?: string
  title: string
}

defineProps({
  list: {
    type: Array<Item>,
    default: () => []
  }
})

const activeIndex = ref(0)

const tabChange = (index: number) => {
  activeIndex.value = index
}
</script>
<style lang="scss" scoped>
.accordion {
  position: relative;
  width: 1181px;
  height: 512px;
  display: flex;
  color: #fff;
  background: url('@/assets/images/bg_shoufq.png');
  overflow: hidden;
}
.item__box {
  position: relative;
  display: flex;
  overflow: hidden;
  margin-left: 4px;
}
.item__content {
  flex-shrink: 0;
  width: 0;
  left: 1000px;
  overflow: hidden;
  transition: all 0.5s ease;
}
.item__title {
  width: 110px;
  flex-shrink: 0;
  background: #00398e;
}
.item__content__detail {
  width: 842px;
  height: 512px;
  opacity: 0;
  transition: opacity 0.5s ease;
}
.item__content-active {
  width: 842px;
  left: 0;
  .item__content__detail {
    opacity: 1;
  }
}
.item__title__detail {
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  width: 100%;
  height: 512px;
  cursor: pointer;

  &__text {
    writing-mode: vertical-lr;
    height: 160px;
    font-size: 28px;
    font-family: PingFangSC-Semibold, PingFang SC;
    font-weight: 600;
    color: #ffffff;
    line-height: 40px;
    letter-spacing: 8px;
  }
}
.item__title-active {
  background: linear-gradient(180deg, #ffbb1a 0%, #f57c00 100%);
}

@keyframes moveInRight {
  from {
    transform: translateX(100%);
  }
  to {
    transform: translateX(0);
  }
}
</style>

使用

<template>
  <div class="container">
    <Accordion class="three__box__text" :list="dataOpenList">
      <template #item__content0>
        <div class="edu__gaikuang">11</div>
      </template>
      <template #item__content1>
        <div class="edu__gongbao">22</div>
      </template>
      <template #item__content2>
        <div class="edu_nianjian">33</div>
      </template>
    </Accordion>
  </div>
</template>
<script lang="ts" setup>
import { reactive, toRefs, onBeforeMount, onMounted } from 'vue'
import Accordion from '@/components/accordion.vue'

const dataOpenList = reactive([
  {
    // icon: 'icon/icon_edu_gk.png',
    // activeIcon: 'icon/icon_edu_gk_active.png',
    title: '教育概况'
  },
  {
    // icon: 'icon/icon_edu_nb.png',
    // activeIcon: 'icon/icon_edu_nb_active.png',

    title: '教育公报'
  },
  {
    // icon: 'icon/icon_edu_nj.png',
    // activeIcon: 'icon/icon_edu_nj_active.png',
    title: '教育年鉴'
  }
])
</script>
<style lang="scss" scoped></style>

在这里插入图片描述
效果
在这里插入图片描述

结语

根据此思路,可以自己实现不同方向和不同排列方式的手风琴效果。

  • 3
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ZSK6

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值