Accordion 아코디언 — 페이지 내비게이션을 우아하게 정리하는 컴포넌트
vue-devui의 d-accordion은 메뉴를 그룹으로 묶어 펼치고 접을 수 있는 아코디언형 내비게이션 컴포넌트예요. 데이터만 바꿔 끼우면 바로 쓸 수 있어서 왼쪽 메뉴 만들 때 특히 편해요.
출처: 문서
본문
페이지에 내비게이션을 제공하는 컴포넌트예요.
언제 사용하나요?
메뉴를 그룹으로 묶어서 정리하고 싶을 때 사용해요.
기본 사용법
메뉴 데이터를 넘겨 주고, 하위 항목을 펼칠 수 있는 메뉴의 열림/닫힘 이벤트(menuToggle)나 클릭 가능한 메뉴의 클릭 이벤트(itemClick)를 받아 보세요. 펼칠 수 있는 메뉴는 open 속성으로 기본 펼침 상태를, 클릭 가능한 메뉴는 active 속성으로 기본 활성 상태를, 비활성 항목은 disabled로 설정해요. restrictOneOpen으로 1단계 메뉴를 하나만 펼칠지 제한할 수도 있어요.
:::demo
<template>
<div class="basic-menu">
<d-accordion
:data="menu"
:accordionType="accordionTypeEmbed ? 'embed' : 'normal'"
:restrictOneOpen="restrictOneOpen"
@itemClick="itemClick"
@menuToggle="menuToggle"
:loadingTemplate="false"
>
<template #loadingTemplate="{ item, deepth }">
<li class="devui-accordion-item">
<div class="devui-accordion-item-title devui-over-flow-ellipsis" style="{{ textIndent: deepth * 20 + 'px' }}">自定义加载...</div>
</li>
</template>
</d-accordion>
</div>
<div class="basic-option">
<d-switch v-model="restrictOneOpen"></d-switch>
Only one level-1 menu can be expanded.
<!--限制只能展开一个一级菜单-->
</div>
<div class="basic-option">
<d-switch v-model="accordionTypeEmbed"></d-switch>
Embedded menu (no shadow)
<!--内嵌菜单形式(无阴影)-->
</div>
</template>
<script lang="ts">
import { defineComponent, ref } from 'vue';
export default defineComponent({
name: 'accordion',
setup() {
const restrictOneOpen = ref(false);
const accordionTypeEmbed = ref(false);
const menu = ref([
{
title: 'Content 1',
children: [{ title: 'Child Content 1' }, { title: 'Child Content 2' }, { title: 'Child Content ' }],
},
{
title: 'Content 2(This is a long sentence for option display.)',
children: [
{ title: 'Child Content 1 (This is a long sentence for option display.)' },
{ title: 'Child Content 2' },
{ title: 'Child Content 3' },
],
},
{
title: 'Content 3 (Default Open)',
open: true,
children: [
{ title: 'Child Content 1 (Disabled)', disabled: true },
{ title: 'Child Content 2 (Default Active)', active: true },
{ title: 'Child Content 3' },
],
},
{
title: 'Content 4 (No Child)',
children: [],
},
{
title: 'Content 5 (Disabled)',
disabled: true,
children: [],
},
{
title: 'Content 6 (Dynamic Content)',
needLoadChildren: true,
loading: false,
children: [],
},
]);
const itemClick = (event) => {
console.log('item click' + JSON.stringify(event));
};
const menuToggle = (event) => {
console.log('menu toggle' + JSON.stringify(event));
if (event.open && event.item.needLoadChildren) {
event.item.loading = true;
setTimeout(() => {
event.item.children = [{ title: 'Child Content 1' }, { title: 'Child Content 2' }];
event.item.needLoadChildren = false;
event.item.loading = false;
}, 2000);
}
};
return {
menu,
restrictOneOpen,
accordionTypeEmbed,
itemClick,
menuToggle,
};
},
});
</script>
<style scoped lang="scss">
.basic-menu {
width: 200px;
}
.basic-option {
line-height: 20px;
vertical-align: middle;
margin-top: 20px;
}
.basic-option > d-toggle {
display: inline-block;
transform: translateY(3px);
}
@media (max-width: 250px) {
.basic-menu {
width: 80%;
}
}
</style>
:::
내장 라우트와 링크 타입 사용하기
linkType을 설정하면 여러 내장 라우트/링크 타입을 바꿔가며 쓸 수 있어요: 기본 타입 ''; 라우트 타입 'routerLink'; 외부 링크 타입 'hrefLink'; 데이터에 따라 라우트나 링크 타입을 판단하는 'dependOnLinkTypeKey'.
:::demo
<template>
<div class="menu-container">
<div class="menu-wrapper">
<div>
router link (recommended)
<!--路由链接(推荐使用)-->
</div>
<d-accordion :data="menu1" class="menu" linkType="routerLink"></d-accordion>
</div>
<div class="menu-wrapper">
<div>
original hyperlink (cross site scene)
<!--原生超链接(涉及跨站场景使用)-->
</div>
<d-accordion :data="menu2" class="menu" linkType="hrefLink"></d-accordion>
</div>
<div class="menu-wrapper">
<div>
mix link (partial cross site scene)
<!--混合链接(部分涉及跨站场景使用)-->
</div>
<d-accordion :data="menu3" class="menu" linkType="dependOnLinkTypeKey"></d-accordion>
</div>
</div>
</template>
<script lang="ts">
import { defineComponent, ref } from 'vue';
export default defineComponent({
name: 'accordion',
setup() {
const menu1 = ref([
{
title: 'Basic',
children: [
{ title: 'Accordion', link: '/components/accordion/' },
{ title: 'Anchor', link: '/components/anchor/' },
{ title: 'Button', link: '/components/button/' },
],
},
{
title: 'Advanced',
children: [
{ title: 'Data Table (disabled)', disabled: true, link: '/components/datatable/' },
{
title: 'Drag Drop (parameter example)',
link: '/components/dragdrop/?query=foo#bar',
},
],
},
{
title: 'Others',
children: [
{ title: 'Icon Library', link: '/components/icon/' },
{ title: 'Home Page', disabled: true, link: '/' },
],
},
]);
const menu2 = ref([
{
title: 'Basic',
children: [
{ title: 'Alert', link: '/components/alert/', target: '_self' },
{ title: 'Anchor', link: '/components/anchor/', target: '_self' },
{ title: 'Accordion', link: '/components/accordion/', target: '_self' },
],
},
{
title: 'Advanced',
children: [
{
title: 'Data Table (disabled)',
disabled: true,
link: '/components/datatable/',
target: '_self',
},
{ title: 'Drag Drop', link: '/components/dragdrop/', target: '_self' },
],
},
{
title: 'Others',
children: [
{ title: 'Icon Library', link: '/components/icon/', target: '_self' },
{ title: 'Home Page(open blank page)', link: '/', target: '_blank' },
],
},
]);
const menu3 = ref([
{
title: 'Basic',
children: [
{ title: 'Alert', link: '/components/alert/', linkType: 'routerLink' },
{ title: 'Anchor', link: '/components/anchor/', linkType: 'routerLink' },
{ title: 'Button', link: '/components/button/', linkType: 'routerLink' },
],
},
{
title: 'Advanced',
children: [
{
title: 'Data Table (disabled)',
disabled: true,
link: '/components/datatable/',
linkType: 'routerLink',
},
{ title: 'Drag Drop', link: '/components/dragdrop/', linkType: 'routerLink' },
],
},
{
title: 'Others',
children: [
{ title: 'Icon Library', link: '/components/icon/', linkType: 'routerLink' },
{ title: 'Home Page(External link open in this window)', link: '/', linkType: 'hrefLink' },
],
},
]);
return {
menu1,
menu2,
menu3,
};
},
});
</script>
<style scoped>
.menu {
width: 200px;
}
.menu-container {
overflow: auto;
padding-left: 2px;
}
.menu-wrapper {
float: left;
}
.menu-wrapper + .menu-wrapper {
margin-left: 20px;
}
:host::after {
content: '';
display: block;
clear: both;
}
@media (max-width: 800px), (min-width: 1024px) and (max-width: 1100px), (min-width: 1280px) and (max-width: 1480px) {
.menu-wrapper {
float: none;
}
.menu-wrapper + .menu-wrapper {
margin-top: 20px;
margin-left: 0;
}
}
@media (max-width: 250px) {
.menu {
width: 80%;
}
}
.menu-wrapper > div {
margin-bottom: 8px;
}
</style>
:::
템플릿 사용하기
펼칠 수 있는 메뉴와 클릭 가능한 메뉴에 각각 다른 템플릿을 쓸 수 있어요. 펼칠 수 있는 메뉴는 menuItemTemplate을, 클릭 가능한 메뉴는 itemTemplate을 지정해요. 데이터가 없을 때는 noContentTemplate을 지정하고, showNoContent로 데이터가 없을 때 펼치지 않도록 조절할 수 있어요. 로딩 중 템플릿은 loadingTemplate으로 지정하고, item의 loadingKey에 해당하는 속성 값으로 로딩 중 표시 여부를 조절해요.
:::demo
<template>
<div class="use-template-menu">
<d-accordion
:data="menu"
:accordionType="accordionTypeEmbed ? 'embed' : 'normal'"
:restrictOneOpen="restrictOneOpen"
@itemClick="itemClick"
@menuToggle="menuToggle"
>
<template #menuItemTemplate="{ item, deepth, parent }">
{{ item.title }}
<span class="use-template-badge" v-if="item.children?.length">
{{ item.children.length }}
</span>
<span class="operation-clear" v-if="item.needLoadChildren === false" @click="clearChildrenData($event, item)">
reset
<!--重置-->
</span>
</template>
<template #itemTemplate="{ item, deepth, parent }">
{{ item.title }}
<span class="use-template-info">(Click Count: {{ item.clicktimes || '0' }})</span>
</template>
<template #noContentTemplate="{ deepth }">
<li class="devui-accordion-item disabled">
<div class="devui-accordion-item-title devui-over-flow-ellipsis disabled" style="{{ textIndent: deepth * 20 + 'px' }}">
Not available yet. Please wait.
<!--尚未开放,敬请期待...-->
</div>
</li>
</template>
<template #loadingTemplate="{ item }">
<li class="devui-accordion-item">
<div class="use-template-loading">
<span class="use-template-circle-spinner"></span>
loading...
<!--正在用力地加载中...-->
</div>
</li>
</template>
</d-accordion>
</div>
</template>
<script lang="ts">
import { defineComponent, ref } from 'vue';
export default defineComponent({
name: 'accordion',
setup() {
const restrictOneOpen = ref(false);
const accordionTypeEmbed = ref(false);
const menu = ref([
{
title: 'Content 1',
open: true,
children: [{ title: 'Child Content 1' }, { title: 'Child Content 2' }],
},
{
title: 'Content 2',
children: [{ title: 'Child Content 1' }, { title: 'Child Content 2' }, { title: 'Child Content 3' }, { title: 'Child Content 4' }],
},
{
title: 'Content 3',
children: [{ title: 'Child Content 1 (disabled)', disabled: true }, { title: 'Child Content 2' }, { title: 'Child Content 3' }],
},
{
title: 'Content 4 (Custom No Data Template)',
children: [], // 可展开菜单节点必须有children非undefined
},
{
title: 'Content 5 (Custom loading Template)',
needLoadChildren: true,
loading: false,
children: [],
},
]);
const childrenData = ref([
{ title: 'Child Content 1' },
{ title: 'Child Content 2' },
{ title: 'Child Content 3' },
{ title: 'Child Content 4' },
{ title: 'Child Content 5' },
{ title: 'Child Content 6' },
{ title: 'Child Content 7' },
]);
const itemClick = (event) => {
event.item.clicktimes = (event.item.clicktimes || 0) + 1;
};
const menuToggle = (event) => {
if (event.open && event.item.needLoadChildren) {
event.item.loading = true;
setTimeout(() => {
event.item.children = childrenData.value;
event.item.needLoadChildren = false;
event.item.loading = false;
}, 1000);
}
};
const clearChildrenData = (event, item) => {
event.stopPropagation();
item.children = [];
item.needLoadChildren = true;
item.open = false;
};
return {
menu,
restrictOneOpen,
accordionTypeEmbed,
itemClick,
menuToggle,
clearChildrenData,
};
},
});
</script>
<style scoped>
.use-template-menu {
width: 400px;
}
.use-template-badge {
display: inline-block;
width: 16px;
height: 16px;
border-radius: 8px;
font-size: 12px;
line-height: 16px;
color: #ffffff;
text-align: center;
background: #5e7ce0;
font-weight: normal;
}
.use-template-loading {
position: relative;
line-height: 40px;
padding-left: 64px;
}
.use-template-circle-spinner {
top: 10px;
left: 36px;
position: absolute;
display: block;
width: 20px;
height: 20px;
transform-origin: center;
animation: circle infinite 0.75s linear;
border: 2px solid #5e7ce0;
border-top-color: transparent;
border-radius: 50%;
}
@keyframes circle {
0% {
transform: rotate(0);
}
100% {
transform: rotate(360deg);
}
}
@media (max-width: 500px) {
.use-template-menu {
width: 80%;
}
}
</style>
:::
내부 리스트는 innerListTemplate을 지정해서 템플릿을 사용해요.
:::demo
<template>
<div class="inner-template-menu">
<d-accordion :data="menu" :accordionType="accordionTypeEmbed ? 'embed' : 'normal'" :restrictOneOpen="restrictOneOpen">
<template #innerListTemplate="{ item, deepth }">
<div class="devui-accordion-submenu devui-accordion-show-animate inner-template-my-menu">
{{ item.content }}
</div>
</template>
</d-accordion>
</div>
</template>
<script lang="ts">
import { defineComponent, ref } from 'vue';
export default defineComponent({
name: 'accordion',
setup() {
const restrictOneOpen = ref(false);
const accordionTypeEmbed = ref(false);
const menu = ref([
{
title: 'Content 1',
children: [],
content: 'Child Content of Content 1',
},
{
title: 'Content 2',
children: [],
content: 'Child Content of Content 2',
},
]);
return {
menu,
restrictOneOpen,
accordionTypeEmbed,
};
},
});
</script>
<style scoped>
.inner-template-menu {
width: 400px;
}
.inner-template-my-menu {
min-height: 60px;
line-height: 40px;
padding: 12px;
}
@media (max-width: 500px) {
.inner-template-menu {
width: 80%;
}
}
</style>
:::
복합 계층과 자동 펼침
여러 계층을 지원하고 중첩 계층 수에 제한이 없어요. autoOpenActiveMenu를 단독으로 사용하면 활성화된 메뉴의 부모 계층을 자동으로 펼쳐 줘요.
:::demo
<template>
<div class="multi-child-menu">
<d-accordion :data="menu" :autoOpenActiveMenu="autoOpenActiveMenu"></d-accordion>
</div>
<div class="multi-child-option">
<d-switch v-model="autoOpenActiveMenu"></d-switch>
auto expend active menu
<!--활성화된 메뉴 자동 펼치기-->
</div>
</template>
<script lang="ts">
import { defineComponent, ref } from 'vue';
export default defineComponent({
name: 'accordion',
setup() {
const autoOpenActiveMenu = ref(false);
const menu = ref([
{
title: 'Content 1 (as a leaf menu)',
},
{
title: 'Content 2 (as a parent menu, has children)',
children: [{ title: 'Child Content 1' }, { title: 'Child Content 2' }, { title: 'Child Content 3' }],
},
{
title: 'Content 3 (as a parent menu, has children)',
children: [
{
title: 'Child Content 1 (has children)',
children: [{ title: 'Child Content 1' }, { title: 'Child Content 2', active: true }, { title: 'Child Content 3' }],
},
{
title: 'Child Content 2 (has children',
children: [
{ title: 'Child Content 1' },
{
title: 'Child Content 2 (has children',
children: [{ title: 'Child Content 1' }, { title: 'Child Content 2' }, { title: 'Child Content 3' }],
},
{ title: 'Child Content 3' },
],
},
{ title: 'Child Content 2' },
{ title: 'Child Content 3' },
],
},
{
title: 'Content 4 (as a parent menu, has no child)',
children: [],
},
]);
return {
menu,
autoOpenActiveMenu,
};
},
});
</script>
<style scoped>
.multi-child-menu {
width: 400px;
}
.multi-child-option {
line-height: 20px;
vertical-align: middle;
margin-top: 20px;
}
.multi-child-option > d-toggle {
display: inline-block;
transform: translateY(3px);
}
@media (max-width: 500px) {
.multi-child-menu {
width: 80%;
}
}
</style>
:::
키 값 바꾸기
titleKey, childrenKey, disabledKey, activeKey 등으로 배열의 키 값을 바꿔서 서로 다른 인터페이스 타입 정의에 맞출 수 있어요.
:::demo
<template>
<div class="change-key-menu">
<d-accordion
:data="menu"
:titleKey="key?.titleKey"
:activeKey="key?.activeKey"
:disabledKey="key?.disabledKey"
:openKey="key?.openKey"
:childrenKey="key?.childrenKey"
></d-accordion>
</div>
</template>
<script lang="ts">
import { defineComponent, reactive, ref } from 'vue';
export default defineComponent({
name: 'accordion',
setup() {
const key = reactive({
titleKey: 'value',
activeKey: '$selected',
disabledKey: 'forbidden',
openKey: '$show',
childrenKey: 'subs',
});
const menu = ref([
{
value: 'Content 1',
},
{
value: 'Content 2 (expended)',
$show: true,
subs: [
{ value: 'Child Content 1 (disabled)', forbidden: true },
{ value: 'Child Content 2 (active)', $selected: true },
{ value: 'Child Content 3' },
],
},
]);
return {
menu,
key,
};
},
});
</script>
<style scoped>
.change-key-menu {
width: 400px;
}
@media (max-width: 500px) {
.change-key-menu {
width: 80%;
}
}
</style>
:::
Accordion 파라미터
| 파라미터 | 타입 | 기본값 | 설명 | Demo 링크 |
|---|---|---|---|---|
| data | Array<any> | AccordionMenuType |
-- | 필수, 데이터 소스, 직접 만든 배열이나 미리 정의된 AccordionMenuType을 사용할 수 있어요 |
기본 사용법 |
| titleKey | string |
'title' | 선택, 제목의 속성 이름, item[titleKey] 타입은 string, 제목 표시 내용이에요 |
키 값 바꾸기 |
| loadingKey | string |
'loading' | 선택, 하위 메뉴가 로딩 중인지 판단하는 속성 이름, item[loadingKey] 타입은 boolean |
키 값 바꾸기 |
| childrenKey | string |
'children' | 선택, 하위 메뉴의 속성 이름, item[childrenKey] 타입은 Array<any> |
키 값 바꾸기 |
| disabledKey | string |
'disabled' | 선택, 비활성 여부의 속성 이름, item[disabledKey] 타입은 boolean |
키 값 바꾸기 |
| activeKey | string |
'active' | 선택, 하위 메뉴가 활성화됐는지의 속성 이름, item[activeKey] 타입은 boolean |
키 값 바꾸기 |
| openKey | string |
'open' | 선택, 메뉴가 펼쳐졌는지의 속성 이름, item[openKey] 타입은 boolean |
키 값 바꾸기 |
| restrictOneOpen | boolean |
false | 선택, 1단계 메뉴를 동시에 하나만 열도록 제한, 기본은 제한 없음 | 기본 사용법 |
| menuItemTemplate | boolean |
true | 선택, 펼칠 수 있는 메뉴 내용 항목 템플릿, 쓸 수 있는 변수는 아래 참고 | 템플릿 사용하기 |
| itemTemplate | boolean |
true | 선택, 클릭 가능한 메뉴 내용 항목 템플릿, 쓸 수 있는 변수는 아래 참고 | 템플릿 사용하기 |
| noContentTemplate | boolean |
true | 선택, 내용이 없을 때 사용자 지정 템플릿 사용, 쓸 수 있는 변수는 아래 참고 | 템플릿 사용하기 |
| loadingTemplate | boolean |
true | 선택, 로딩 중 사용자 지정 템플릿, 쓸 수 있는 변수는 아래 참고 | 템플릿 사용하기 |
| innerListTemplate | boolean |
true | 선택, 하위 리스트 내용을 완전히 직접 꾸미기, 접이식 패널로 활용, 쓸 수 있는 변수는 아래 참고 | 템플릿 사용하기 |
| linkType | 'routerLink'|'hrefLink'|'dependOnLinkTypeKey'|'' |
'' | 선택, 'routerLink'는 라우트 시나리오; 'hrefLink'는 외부 링크 시나리오; 'dependOnLinkTypeKey'는 동적 라우트 또는 외부 링크 시나리오; ''는 기본 비링크 타입 (우클릭으로 새 탭 열기 불가) |
내장 라우트와 링크 타입 사용하기 |
| linkTypeKey | string |
'linkType' | 선택, 링크 내용 타입의 key 값, linkType이 'dependOnLinkTypeKey'일 때 객체의 링크 타입 속성 이름을 지정해요. item[linkTypeKey] 타입은 'routerLink'|'hrefLink'| string이고, 'routerLink'는 라우트 링크, 'hrefLink'는 외부 링크, 그 외는 기본 비링크 타입이에요 |
|
| linkKey | string |
'link' | 선택, 링크 내용의 key, linkType이 ''가 아닌 링크 타입일 때 링크 값을 가져오는 속성 값, item[linkKey]는 라우트 주소나 하이퍼링크 주소예요 |
|
| linkTargetKey | string |
'target' | 선택, 링크 대상 창의 key, 링크 타입에서 사용, item[linkTargetKey]는 개별 링크의 대상 창이에요 | |
| linkDefaultTarget | string |
'_self' | 선택, target을 설정하지 않았을 때의 target 기본값은 '_self', 링크 타입에서 사용, a 링크의 target 속성과 같은 값을 가져요 |
내장 라우트와 링크 타입 사용하기 |
| autoOpenActiveMenu | boolean |
false | 선택, 활성화된 하위 항목이 있는 메뉴를 자동으로 펼칠지 여부 | 복합 계층과 자동 펼침 |
| accordionType | 'normal'|'embed' |
'normal' | 선택, 메뉴 형태가 일반(그림자 있음)인지 내장(그림자 없음)인지 | 기본 사용법 |
| showAnimation | boolean |
true | 선택, 애니메이션을 표시할지 여부 | 내장 라우트와 링크 타입 사용하기 |
Accordion 이벤트
| 이벤트명 | 타입 | 설명 | Demo 링크 |
|---|---|---|---|
| menuToggle | EventEmitter<AccordionMenuToggleEvent> |
선택, 펼칠 수 있는 메뉴의 펼침 이벤트, 반환 객체의 item 속성은 클릭한 객체 데이터, open이 true면 펼칠 예정 false면 닫을 예정, parent는 부모 객체 데이터, event는 클릭 이벤트의 원본 이벤트 | 기본 사용법 |
| itemClick | EventEmitter<AccordionItemClickEvent> |
선택, 클릭 가능한 메뉴의 클릭 이벤트, 반환 객체의 item 속성은 클릭한 객체 데이터, preActive 객체는 이전에 펼쳐졌던 객체, parent는 부모 객체 데이터, event는 클릭 이벤트의 원본 이벤트 | 기본 사용법 |
| activeItemChange | EventEmitter<any> |
선택, 하위 항목이 바뀔 때 새로 활성화된 하위 항목의 데이터를 발행해요 | 기본 사용법 |
Accordion 타입 정의
/* 基础数据类型 */
type AccordionMenuItemLinkType = 'routerLink' | 'hrefLink' | string;
export interface AccordionBase {
title: string;
disabled?: boolean;
[prop: string]: any;
}
interface IAccordionActiveable {
active?: boolean;
}
interface IAccordionFoldable<T> {
open?: boolean;
loading?: boolean;
children?: Array<T>;
}
interface IAccordionLinkable {
link?: string;
target?: boolean;
linkType?: AccordionMenuItemLinkType;
}
export interface AccordionBaseItem extends AccordionBase, IAccordionActiveable {}
export interface AccordionBaseMenu<T> extends AccordionBase, IAccordionFoldable<T> {}
export interface AccordionLinkableItem extends AccordionBase, IAccordionActiveable, IAccordionLinkable {}
export interface AccordionMenuItem extends AccordionBase, IAccordionActiveable, IAccordionFoldable<AccordionMenuItem>, IAccordionLinkable {}
export type AccordionMenuType = Array<AccordionMenuItem>;
/* 基础事件类型 */
export interface AccordionMenuToggleEvent {
item: any;
open: boolean;
parent: any;
event: MouseEvent;
}
export interface AccordionItemClickEvent {
item: any;
prevActiveItem?: any;
parent: any;
event: MouseEvent;
}
/* 废弃接口 */
/** @deprecated merge into `AccordionMenuItem`*/
export interface AccordionSubMenuItem {
title: string;
active?: boolean;
disabled?: boolean;
[prop: string]: any;
}
/** @deprecated use `AccordionLinkableItem` instead*/
export interface AccordionSubMenuItemHrefLink {
title: string;
link: string;
target?: string;
active?: boolean;
disabled?: boolean;
[prop: string]: any;
}
/** @deprecated use `AccordionLinkableItem` instead*/
export interface AccordionSubMenuItemRouterLink {
title: string;
link: string;
target?: string;
active?: boolean;
disabled?: boolean;
[prop: string]: any;
}
/** @deprecated use `AccordionLinkableItem` instead*/
export interface AccordionSubMenuItemDynamicLink {
title: string;
link: string;
linkType: 'routerLink' | 'hrefLink' | string;
target?: string;
active?: boolean;
disabled?: boolean;
[prop: string]: any;
}
AccordionProps
import { ExtractPropTypes } from 'vue';
import { AccordionMenuType } from './accordion.type';
export const accordionProps = {
data: {
type: Array as () => Array<any> | AccordionMenuType,
default: null,
},
/* Key值定义, 用于自定义数据结构 */
titleKey: { type: String, default: 'title' }, // 标题的key,item[titleKey]类型为string,为标题显示内容
loadingKey: { type: String, default: 'loading' }, // 子菜单动态加载item[loadingKey]类型为boolean
childrenKey: { type: String, default: 'children' }, // 子菜单Key
disabledKey: { type: String, default: 'disabled' }, // 是否禁用Key
activeKey: { type: String, default: 'active' }, // 菜单是否激活/选中
openKey: { type: String, default: 'open' }, // 菜单是否打开
/* 菜单模板 */
menuItemTemplate: { type: Boolean, default: true }, // 可展开菜单内容条模板
itemTemplate: { type: Boolean, default: true }, // 可点击菜单内容条模板
menuToggle: {
type: Function as unknown as () => (event: MouseEvent) => void,
default: null,
}, // 可展开菜单展开事件
itemClick: {
type: Function as unknown as () => (event: MouseEvent) => void,
default: null,
}, // 可点击菜单点击事件
activeItemChange: {
type: Function as unknown as () => (event: MouseEvent) => void,
default: null,
},
/** 高级选项和模板 */
restrictOneOpen: { type: Boolean, default: false }, // 限制一级菜单同时只能打开一个
autoOpenActiveMenu: { type: Boolean, default: false }, // 自动展开活跃菜单
showNoContent: { type: Boolean, default: true }, // 没有内容的时候是否显示没有数据
noContentTemplate: { type: Boolean, default: true }, // 没有内容的时候使用自定义模板
loadingTemplate: { type: Boolean, default: true }, // 加载中使用自定义模板
innerListTemplate: { type: Boolean, default: true }, // 可折叠菜单内容完全自定义,用做折叠面板
/* 内置路由/链接/动态判断路由或链接类型 */
linkType: {
type: String as () => 'routerLink' | 'hrefLink' | 'dependOnLinkTypeKey' | '' | string,
default: '',
},
linkTypeKey: { type: String, default: 'linkType' }, // linkType为'dependOnLinkTypeKey'时指定对象linkType定义区
linkKey: { type: String, default: 'link' }, // 链接内容的key
linkTargetKey: { type: String, default: 'target' }, // 链接目标窗口的key
linkDefaultTarget: { type: String, default: '_self' }, // 不设置target的时候target默认值
accordionType: {
type: String as () => 'normal' | 'embed',
default: 'normal',
},
} as const;
export type AccordionProps = ExtractPropTypes<typeof accordionProps>;
템플릿에서 쓸 수 있는 변수 값 (사용 방법은 아래와 같아요)
<template #templateName="{item}">{{item}}</template>
menuItemTemplate에서 쓸 수 있는 변수 값
| 변수 | 타입 | 변수 의미 설명 |
|---|---|---|
| item | any |
펼침 타입 메뉴 데이터 |
| deepth | number |
중첩 구조 계층을 나타내요 |
| parent | any |
상위 부모 메뉴 데이터 |
| ~~~titleKey~~~ | string |
이미 폐기됨~~~컴포넌트의 titleKey 값~~~ |
| ~~~disabledKey~~~ | string |
이미 폐기됨~~~컴포넌트의 disabledKey 값~~~ |
| ~~~openKey~~~ | string |
이미 폐기됨~~~컴포넌트의 openKey 값~~~ |
| ~~~menuToggleFn~~~ | Function |
이미 폐기됨~~~인자는 item이어야 하고, 1단계 메뉴가 클릭됐음을 나타내요~~~ |
itemTemplate에서 쓸 수 있는 변수 값
| 변수 | 타입 | 변수 의미 설명 |
|---|---|---|
| item | any |
클릭 타입 메뉴 데이터 |
| deepth | number |
값은 중첩 구조 계층을 나타내요 |
| parent | any |
상위 부모 메뉴 데이터 |
| ~~~titleKey~~~ | string |
이미 폐기됨~~~ 컴포넌트의 titleKey 값~~~ |
| ~~~disabledKey~~~ | string |
이미 폐기됨~~~ 컴포넌트의 disabledKey 값~~~ |
| ~~~activeKey~~~ | string |
이미 폐기됨~~~ 컴포넌트의 activeKey 값~~~ |
| ~~~itemClickFn~~~ | Function |
이미 폐기됨~~~인자는 item이어야 하고, 2단계 메뉴가 클릭됐음을 나타내요~~~ |
noContentTemplate에서 쓸 수 있는 변수 값
| 변수 | 타입 | 변수 의미 설명 |
|---|---|---|
| item | any |
부모 메뉴의 개별 데이터 |
| deepth | number |
값은 중첩 구조 계층을 나타내요 |
loadingTemplate에서 쓸 수 있는 변수 값
| 변수 | 타입 | 변수 의미 설명 |
|---|---|---|
| item | any |
부모 메뉴의 개별 데이터 |
| deepth | number |
값은 중첩 구조 계층을 나타내요 |
| ~~~loadingKey~~~ | string |
~~~컴포넌트의 loadingKey 값~~~ |
innerListTemplate에서 쓸 수 있는 변수 값
| 변수 | 타입 | 변수 의미 설명 |
|---|---|---|
| item | any |
부모 메뉴의 개별 데이터 |
| deepth | number |
값은 중첩 구조 계층을 나타내요 |
| ~~~titleKey~~~ | string |
이미 폐기됨~~~컴포넌트의 titleKey 값~~~ |
| ~~~loadingKey~~~ | string |
이미 폐기됨~~~컴포넌트의 loadingKey 값~~~ |
| ~~~childrenKey~~~ | string |
이미 폐기됨~~~컴포넌트의 childrenKey 값~~~ |
| ~~~disabledKey~~~ | string |
이미 폐기됨~~~컴포넌트의 disabledKey 값~~~ |
| ~~~openKey~~~ | string |
이미 폐기됨~~~컴포넌트의 openKey 값~~~ |
| ~~~activeKey~~~ | string |
이미 폐기됨~~~컴포넌트의 activeKey 값, 2단계 메뉴에서 사용~~~ |
| menuToggleFn | Function |
인자는 item이어야 하고, 메뉴가 펼쳐졌음을 나타내요. 선택 인자 event는 원본 이벤트예요 |
| itemClickFn | Function |
인자는 클릭 가능한 메뉴의 item이어야 하고, 메뉴가 클릭됐음을 나타내요. 선택 인자 event는 원본 이벤트예요 |
더 알아보기 (Learn more)
d-accordion은 데이터 주도로 메뉴를 그리기 때문에 라우트 링크, 사용자 지정 템플릿, 키 값 변경 같은 확장 포인트가 넉넉한 편이에요. 실제 사이드바를 만들 때는 linkType과 각종 템플릿 슬롯을 조합해 보는 걸 추천해요.