-
递归组件实战
views/layout.vue
<template>
<div class="layout-wrapper">
<Layout class="layout-outer">
<Sider collapsible v-model="collapsed" hide-trigger breakpoint="sm">
<side-menu :collapsed="collapsed" :list="menuList"></side-menu>
</Sider>
<Layout>
<Header class="header-wrapper">
<Icon type="md-menu" :size="32" @click.native="handleCollapsed" :class="triggerClasses"/>
</Header>
<Content class="content-con">
<Card shadow class="page-card">
<router-view/>
</Card>
</Content>
</Layout>
</Layout>
</div>
</template>
<script>
import SideMenu from '_c/side-menu'
export default {
data () {
return {
collapsed: true,
menuList: [
{
title: '111',
name: 'menu1',
icon: 'md-analytics'
},
{
title: '222',
name: 'menu2',
icon: 'md-analytics'
},
{
title: '333',
name: 'menu3',
icon: 'md-appstore',
children: [
{
title: '333-111',
name: 'menu31',
icon: 'md-apps'
},
{
title: '333-222',
name: 'menu32',
icon: 'md-apps',
children: [
{
title: '333-222-111',
name: 'menu321',
icon: 'ios-archive'
}
]
}
]
}
]
}
},
computed: {
triggerClasses () {
return ['trigger-icon', this.collapsed ? 'rotate' : '']
}
},
components: {
SideMenu
},
methods: {
handleCollapsed () {
this.collapsed = !this.collapsed
}
}
}
</script>
<style lang="less" scoped>
.layout-wrapper,
.layout-outer {
height: 100%;
.header-wrapper {
background: #fff;
box-shadow: 0 1px 1px 1px rgba(0, 0, 0, 0.1);
padding: 0 23px;
.trigger-icon {
cursor: pointer;
transition: transform 0.3s ease;
&.rotate {
transform: rotateZ(-90deg);
transition: transform 0.3s ease;
}
}
}
.content-con {
padding: 10px;
.page-card {
min-height: ~"calc(100vh - 84px)";
}
}
}
</style>
components/side-menu/index.js
import SideMenu from './side-menu.vue'
export default SideMenu
components/side-menu/side-menu.vue
<template>
<div class="side-menu-wrapper">
<slot></slot>
<Menu width="auto" theme="dark" v-show="!collapsed" @on-select="handleSelect">
<template v-for="item in list">
<re-submenu
v-if="item.children"
:key="`menu_${item.name}`"
:name="item.name"
:parent="item"
>
<menu-item></menu-item>
</re-submenu>
<menu-item v-else :key="`menu_${item.name}`" :name="item.name">
<Icon :type="item.icon"/>
{{ item.title }}
</menu-item>
</template>
</Menu>
<div class="drop-wrapper" v-show="collapsed">
<template v-for="item in list">
<re-dropdown @on-select="handleSelect" v-if="item.children" icon-color="#fff" :show-title="false" :key="`drop_${item.name}`" :parent="item"></re-dropdown>
<Tooltip v-else transfer :content="item.title" placement="right" :key="`drop_${item.name}`">
<span @click="handleClick(item.name)" class="drop-menu-span">
<Icon :type="item.icon" color="#fff" :size="30"/>
</span>
</Tooltip>
</template>
</div>
</div>
</template>
<script>
import ReSubmenu from './re-submenu'
import ReDropdown from './re-dropdown'
export default {
name: 'SideMenu',
components: {
ReSubmenu,
ReDropdown
},
props: {
collapsed: {
type: Boolean,
default: false
},
list: {
type: Array,
default: () => []
}
},
methods: {
handleSelect (name) {
console.log(name)
},
handleClick (name) {
console.log(name)
}
}
}
</script>
<style lang="less">
.side-menu-wrapper {
.ivu-tooltip,
.drop-menu-span {
display: block;
width: 100%;
text-align: center;
padding: 10px 0;
}
.drop-wrapper > .ivu-dropdown {
display: block;
padding: 10px;
margin: 0 auto;
}
}
</style>
-
不收缩
<template>
<Submenu :name="parent.name">
<template slot="title">
<Icon :type="parent.icon" />
{{ parent.title }}
</template>
<template v-for="item in parent.children">
<re-submenu
v-if="item.children"
:key="`menu_${item.name}`"
:name="item.name"
:parent="item"
>
</re-submenu>
<menu-item v-else :key="`menu_${item.name}`" :name="item.name">
<Icon :type="item.icon" />
{{ item.title }}
</menu-item>
</template>
</Submenu>
</template>
<script>
export default {
name: 'ReSubmenu',
props: {
parent: {
type: Object,
default: () => ({})
}
}
}
</script>
-
收缩
<template>
<Dropdown @on-click="handleClick" placement="right-start">
<span class="drop-menu-span" :style="titleStyle">
<Icon :type="parent.icon" :color="iconColor" :size="30"></Icon>
<span color="#515a6e" v-if="showTitle">{{ parent.title }}</span>
</span>
<DropdownMenu slot="list">
<template v-for="item in parent.children">
<re-dropdown v-if="item.children" :key="`drop_${item.name}`" :parent="item"></re-dropdown>
<DropdownItem v-else :key="`drop_${item.name}`" :name="item.name">
<Icon :type="item.icon" color="#515a6e" :size="30"></Icon>
{{ item.title }}
</DropdownItem>
</template>
</DropdownMenu>
</Dropdown>
</template>
<script>
export default {
name: 'ReDropdown',
props: {
parent: {
type: Object,
default: () => ({})
},
iconColor: {
type: String,
default: '#515a6e'
},
showTitle: {
type: Boolean,
default: true
}
},
computed: {
titleStyle () {
return {
textAlign: this.showTitle ? 'left' : 'center',
paddingLeft: this.showTitle ? '16px' : ''
}
}
},
methods: {
handleClick (name) {
if (!this.showTitle) this.$emit('on-select', name)
}
}
}
</script>