Vue3實(shí)現(xiàn)折疊面板組件的示例代碼
背景
折疊面板大家都不陌生,很多時(shí)候需要實(shí)現(xiàn)一些復(fù)雜的交互,就會(huì)用到它,簡(jiǎn)潔直觀還美觀,通常我們直接用第三方組件庫就行了,不過只會(huì)用還不行,還要會(huì)寫才行,下面我們一起手寫一個(gè)折疊面板組件。
最終效果
實(shí)現(xiàn)功能
- 手風(fēng)琴模式
- 自定義標(biāo)題
- 自定義內(nèi)容
- 數(shù)據(jù)綁定,支持string | array
實(shí)現(xiàn)邏輯
首先創(chuàng)建組件目錄,如下:
index.vue 實(shí)現(xiàn)代碼:
<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] }, // 數(shù)據(jù)綁定 accordion: { type: Boolean } // 是否開啟手風(fēng)琴模式,默認(rèn)不開啟 }) const emits = defineEmits(['update:modelValue', 'change']) const activeNames = ref([]) onMounted(() => { setValueLists() }) // 初始化設(shè)置激活項(xiàng) const setValueLists = () => { if (!Array.isArray(props.modelValue)) { activeNames['value'] = [props.modelValue] } else { activeNames['value'] = props.modelValue } } // 點(diǎn)擊每項(xiàng)處理函數(shù) const toggle = (name) => { if (activeNames['value'].includes(name)) { // 收起時(shí) activeNames['value'] = activeNames['value'].filter((item) => item != name) } else { // 展開時(shí) 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 實(shí)現(xiàn)代碼
<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) // 開展?fàn)顟B(tài) 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 展開收起動(dòng)畫組件
<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> <!-- 自定義內(nèi)容 --> </template> </collapse-item> <collapse-item :name="2"> <template #title> <!-- 自定義title --> </template> <template #content> <!-- 自定義內(nèi)容 --> </template> </collapse-item> </CollapsePanel> //script const activeName = ref([2]) const accordion ref(true) // 是否開啟手風(fēng)琴模式 // 點(diǎn)擊觸發(fā) const change = (value) => { console.log(value) }
以上就是Vue3實(shí)現(xiàn)折疊面板組件的示例代碼的詳細(xì)內(nèi)容,更多關(guān)于Vue3折疊面板組件的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
使用element組件table表格實(shí)現(xiàn)某條件下復(fù)選框無法勾選
這篇文章主要介紹了使用element組件table表格實(shí)現(xiàn)某條件下復(fù)選框無法勾選問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-03-03vue+px2rem實(shí)現(xiàn)pc端大屏自適應(yīng)的實(shí)例代碼(rem適配)
不管是移動(dòng)端的適配,還是大屏需求,都離不開不一個(gè)單位rem,rem是相對(duì)于根元素的字體大小的單位,下面這篇文章主要給大家介紹了關(guān)于vue+px2rem實(shí)現(xiàn)pc端大屏自適應(yīng)的相關(guān)資料,需要的朋友可以參考下2021-08-08vue路由$router.push()使用query傳參的實(shí)際開發(fā)使用
在vue項(xiàng)目中我們用函數(shù)式編程this.$router.push跳轉(zhuǎn),用query傳遞一個(gè)對(duì)象時(shí)要把這個(gè)對(duì)象先轉(zhuǎn)化為字符串,然后在接收的時(shí)候要轉(zhuǎn)化為對(duì)象,下面這篇文章主要給大家介紹了關(guān)于vue路由$router.push()使用query傳參的實(shí)際開發(fā)使用,需要的朋友可以參考下2022-11-11