vue3手风琴

该文章描述了一个使用Vue.js实现的折叠内容组件。组件基于flex布局,利用CSS过渡效果实现内容推拉动画。每个项目包含标题和内容两部分,内容区域默认隐藏,点击标题显示。组件支持动态内容,使用插槽进行自定义,并提供了当前显示项的属性和方法。
摘要由CSDN通过智能技术生成

结构搭建

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

用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>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值