Vue3实现折叠面板组件的示例代码

 更新时间:2024年01月08日 15:25:54   作者:前端老K  
折叠面板大家都不陌生,很多时候需要实现一些复杂的交互,就会用到它,简洁直观还美观,下面就跟随小编一起学习一下如果使用Vue3实现折叠面板组件吧

背景

折叠面板大家都不陌生,很多时候需要实现一些复杂的交互,就会用到它,简洁直观还美观,通常我们直接用第三方组件库就行了,不过只会用还不行,还要会写才行,下面我们一起手写一个折叠面板组件。

最终效果

实现功能

  • 手风琴模式
  • 自定义标题
  • 自定义内容
  • 数据绑定,支持string | array

实现逻辑

首先创建组件目录,如下:

index.vue 实现代码:

<template>
  <div class="collapse-panel">
    <slot></slot>
  </div>
</template>

<script setup lang="ts">
import { useSlots, ref, onMounted, provide } from 'vue'

const slots = useSlots()
const props = defineProps({
  modelValue: {
    type: [String, Array, Number]
  }, // 数据绑定
  accordion: {
    type: Boolean
  } // 是否开启手风琴模式,默认不开启
})
const emits = defineEmits(['update:modelValue', 'change'])

const activeNames = ref([])

onMounted(() => {
  setValueLists()
})

// 初始化设置激活项
const setValueLists = () => {
  if (!Array.isArray(props.modelValue)) {
    activeNames['value'] = [props.modelValue]
  } else {
    activeNames['value'] = props.modelValue
  }
}
// 点击每项处理函数
const toggle = (name) => {
  if (activeNames['value'].includes(name)) {
    // 收起时 
    activeNames['value'] = activeNames['value'].filter((item) => item != name)
  } else {
    // 展开时
    if (props.accordion) {
      activeNames['value'] = [name]
    } else {
      activeNames['value'].push(name)
    }
  }
  emits('update:modelValue', activeNames['value'])
  emits('change', activeNames['value'])
}

// 提供父组件指定方法
provide('toggle', toggle)
provide('activeNames', activeNames)
</script>

<style lang="less" scoped></style>

CollapseItem.vue 实现代码

<template>
  <div class="collapse-item">
    <div class="collapse-head">
      <el-icon class="caret-down"
               :class="{ 'caret-open': isCollapse }"
               @click.stop="handlePanelItemClick">
        <CaretRight />
      </el-icon>
      <div class="collapse-head-right">
        <span v-if="!slots.title"
              class="collapse-title">{{ attrs.title }}</span>
        <slot name="title"></slot>
      </div>
    </div>
    <CollapseTransition>
      <div v-show="isCollapse"
           class="collapse-content">
        <slot name="content"></slot>
      </div>
    </CollapseTransition>
  </div>
</template>

<script setup lang="ts">
import { ref, useSlots, useAttrs, inject, computed } from 'vue'
import CollapseTransition from './CollapseTransition.vue'
const slots = useSlots()
const attrs = useAttrs()
const activeNames = inject('activeNames')
const handleToggle = inject('toggle')

const status = ref(false) // 开展状态

const isCollapse = computed(() => {
  return activeNames['value'].includes(attrs.name)
})

const handlePanelItemClick = () => {
  handleToggle(attrs.name)
}
</script>

<style scoped lang="less">
.collapse-item {
  display: flex;
  flex-flow: column;
  .collapse-head {
    display: flex;
    flex-flow: row nowrap;
    align-items: center;
    height: 42px;
    background: #d9d9d9;
    padding: 0 14px;
    border: 1px solid #cccccc;
    border-bottom: none;
    border-radius: 4px 4px 0px 0px;
    overflow: hidden;
    .caret-down {
      font-size: 20px;
      color: #1b1b1b;
      margin-right: 6px;
      cursor: pointer;
      transition: transform 0.3s;
      transform-origin: center center;
      &.caret-open {
        transform: rotate(90deg);
      }
    }
    .collapse-head-right {
      flex: 1;
      width: 0;
      .collapse-title {
        font-size: 14px;
        color: #1b1b1b;
      }
    }
  }
  .collapse-content {
  }
}
</style>

CollapseTransition.vue 展开收起动画组件

<template>
  <transition @before-enter="beforeEnter"
              @enter="enter"
              @leave="leave"
              @after-leave="afterLeave">
    <slot></slot>
  </transition>
</template>

<script setup lang="ts">
const beforeEnter = (el) => {
  el.classList.add('collapse-transition')
  el.dataset.oldPaddingTop = el.style.paddingTop
  el.dataset.oldPaddingBottom = el.style.paddingBottom
  el.dataset.oldOverflow = el.style.overflow
  el.style.overflow = 'hidden'
  el.style.height = '0'
  el.style.paddingTop = 0
  el.style.paddingBottom = 0
}
const enter = (el) => {
  el.style.height = el.scrollHeight + 'px'
  el.style.paddingTop = el.dataset.oldPaddingTop
  el.style.paddingBottom = el.dataset.oldPaddingBottom
}

const afterEnter = (el) => {
  el.classList.remove('collapse-transition')
  el.style.height = ''
  el.style.overflow = el.dataset.oldOverflow
}

const beforeLeave = (el) => {
  el.dataset.oldPaddingTop = el.style.paddingTop
  el.dataset.oldPaddingBottom = el.style.paddingBottom
  el.dataset.oldOverflow = el.style.overflow
  el.style.height = el.scrollHeight + 'px'
  el.style.overflow = 'hidden'
}

const leave = (el) => {
  el.classList.add('collapse-transition')
  el.style.height = 0
  el.style.paddingTop = 0
  el.style.paddingBottom = 0
}

const afterLeave = (el) => {
  el.classList.remove('collapse-transition')
  el.style.height = ''
  el.style.overflow = el.dataset.oldOverflow
  el.style.paddingTop = el.dataset.oldPaddingTop
  el.style.paddingBottom = el.dataset.oldPaddingBottom
}
</script>

<style scoped lang="less">
.collapse-transition {
  transition: all 0.3s ease-in-out;
}
</style>

组件的使用

// template
<CollapsePanel v-model="activeName" @change="change" :accordion="accordion">
  <collapse-item :name="1">
    <template #title>
      <!-- 自定义title -->
    </template>
    <template #content>
      <!-- 自定义内容 -->
    </template>
  </collapse-item>
  
  <collapse-item :name="2">
    <template #title>
      <!-- 自定义title -->
    </template>
    <template #content>
      <!-- 自定义内容 -->
    </template>
  </collapse-item>
</CollapsePanel>

//script
const activeName = ref([2])
const accordion ref(true) // 是否开启手风琴模式

// 点击触发
const change = (value) => {
    console.log(value)
}

以上就是Vue3实现折叠面板组件的示例代码的详细内容,更多关于Vue3折叠面板组件的资料请关注脚本之家其它相关文章!

相关文章

  • Vant主题定制如何修改颜色样式

    Vant主题定制如何修改颜色样式

    这篇文章主要介绍了Vant主题定制如何修改颜色样式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-04-04
  • Vue.js每天必学之组件与组件间的通信

    Vue.js每天必学之组件与组件间的通信

    Vue.js每天必学之组件与组件间的通信,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2016-09-09
  • vue页面引入three.js实现3d动画场景操作

    vue页面引入three.js实现3d动画场景操作

    这篇文章主要介绍了vue页面引入three.js实现3d动画场景操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-08-08
  • 使用 Vue 实现一个虚拟列表的方法

    使用 Vue 实现一个虚拟列表的方法

    这篇文章主要介绍了使用 Vue 实现一个虚拟列表的方法,本文通过实例代码给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友可以参考下
    2019-08-08
  • 在vue项目中,将juery设置为全局变量的方法

    在vue项目中,将juery设置为全局变量的方法

    今天小编就为大家分享一篇在vue项目中,将juery设置为全局变量的方法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2018-09-09
  • element-ui upload组件多文件上传的示例代码

    element-ui upload组件多文件上传的示例代码

    这篇文章主要介绍了element-ui upload组件多文件上传的示例代码,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-10-10
  • vue使用SVG实现圆形进度条音乐播放

    vue使用SVG实现圆形进度条音乐播放

    这篇文章主要为大家详细介绍了vue使用SVG实现圆形进度条音乐播放,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-04-04
  • Vue基础之侦听器详解

    Vue基础之侦听器详解

    这篇文章主要为大家介绍了Vue基础之侦听器,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带来帮助
    2021-12-12
  • Vue源码cached解析

    Vue源码cached解析

    最近在写闭包的应用的时候,出现了一个cached函数,来源于Vue源码,利用了闭包变量不会被回收的特点,可以缓存变量,cached本质上是一个高阶函数,它接受一个函数的参数,同时返回一个函数
    2022-08-08
  • Vue.js实现tab切换效果

    Vue.js实现tab切换效果

    这篇文章主要为大家详细介绍了Vue.js实现tab切换效果,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2019-07-07

最新评论