Vue3实现折叠面板组件的示例代码
作者:前端老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折叠面板组件的资料请关注脚本之家其它相关文章!