JSFiddle - React, Tailwind, and code Playground
by kurotanshi
HTML
<script src="https://unpkg.com/vue@next"></script>
<div id="app">
<menu-component :title="menuData.name" :child="menuData.childNodes"></menu-component>
</div>
SCSS
#app {
display: block;
padding: 1rem;
font-size: 1rem;
}
#app > ul {
> li {
margin-left: 0;
}
}
ul > li {
display: block;
margin-left: 1rem;
margin-bottom: 0.5rem;
padding: 5px;
background-color: #eee;
}
h2.has-child {
cursor: pointer;
&::before {
content: '+ ';
}
}
h2.has-child.is-open::before {
content: '- ';
}
JavaScript
const menuData = {
name: '好書推薦',
childNodes: [{
name: 'Git',
childNodes: [{
name: '為你自己學 Git'
}]
},
{
name: '前端開發',
childNodes: [{
name: '金魚都能懂的 CSS 選取器'
},
{
name: '0 陷阱!0 誤解!8 天重新認識 JavaScript!'
},
{
name: '讓 TypeScript 成為你全端開發的 ACE!'
},
]
},
{
name: 'IoT',
childNodes: [{
name: 'IoT沒那麼難!新手用 JavaScript 入門做自己的玩具!'
}]
},
]
};
const app = Vue.createApp({
data() {
return {
menuData
}
}
});
app.component('menu-component', {
name: `menu-component`,
props: {
title: String,
child: {
type: Array,
default: []
}
},
data () {
return {
isOpen: false
}
},
template: `
<ul>
<li>
<template v-if="child.length > 0">
<h2 class="has-child"
:class="{ 'is-open': isOpen }"
@click="isOpen = !isOpen">{{ title }}</h2>
<menu-component
v-show="isOpen"
v-for="c in child"
:title="c.name"
:child="c.childNodes"
/>
</template>
<a v-else>{{ title }}</a>
</li>
</ul>
`
});
app.mount('#app');