<div id="demo"> <ul> <!-- wrap the raw data with `model` alias so we can manage view state without polluting the original data --> <li v-component="folder" v-with="model: treeData"></li> </ul> </div> <script type="text/x-template" id="folder-template"> <div class="item folder" v-on="click: open = !open"> {{model.name}} [{{open ? '-' : '+'}}] </div> <ul v-show="open"> <li v-repeat="model: model.children | orderBy 'type'" v-component="{{model.type}}"> </li> </ul> </script> <script type="text/x-template" id="file-template"> <div class="item file">{{model.name}}</div> </script>
Vue.component('folder', { template: '#folder-template', data: { open: false } }) Vue.component('file', { template: '#file-template' }) var menu = new Vue({ el: '#demo', data: { treeData: { name: 'My Tree', children: [ { type: 'file', name: 'hello' }, { type: 'file', name: 'wat' }, { type: 'folder', name: 'child folder', children: [ { type: 'folder', name: 'child folder', children: [ { type: 'file', name: 'hello' }, { type: 'file', name: 'wat' } ] }, { type: 'file', name: 'hello' }, { type: 'file', name: 'wat' }, { type: 'folder', name: 'child folder', children: [ { type: 'file', name: 'hello' }, { type: 'file', name: 'wat' } ] } ] } ] } } })
.item { cursor: pointer; font-family: monospace; color: #999; } .item.folder { color: #333; } ul { padding-left: 1em; list-style-type: circle; }