Это не имеет ничего общего с VueJS, мы должны поиграть с CSS, установив необходимые свойства CSS, когда узел папки находится в фокусе.
//https://github.com/vuejs/Discussion/issues/356
// demo data
Vue.prototype.$selectedNode = []
var data = {
name: 'My Tree',
children: [{
name: 'hello'
},
{
name: 'wat'
},
{
name: 'child folder',
children: [{
name: 'child folder',
children: [{
name: 'hello'
},
{
name: 'wat'
}
]
},
{
name: 'hello'
},
{
name: 'wat'
},
{
name: 'child folder',
children: [{
name: 'hello'
},
{
name: 'wat'
}
]
}
]
}
]
}
// define the item component
Vue.component('item', {
template: '#item-template',
props: {
model: Object
},
data: function() {
return {
open: false,
selectedNode: []
}
},
computed: {
isFolder: function() {
return this.model.children &&
this.model.children.length
},
setChevronClass: function() {
return {
opened: this.isFolder && this.open,
closed: this.isFolder && !this.open,
folderChevronSpan: this.isFolder
}
},
setSelected: function() {
if (this.selectedNode.length > 0 && this.selectedNode[0].title == this.model.name)
return true;
else
return false;
}
},
methods: {
toggle: function() {
if (this.isFolder) {
this.open = !this.open
this.$refs.toggler.focus();
}
},
changeType: function() {
if (!this.isFolder) {
Vue.set(this.model, 'children', [])
this.addChild()
this.open = true
}
},
addChild: function() {
this.model.children.push({
name: 'new stuff'
})
},
selectNode: function() {
this.selectedNode = [];
this.selectedNode.push({
'title': this.model.name,
'isSelected': true
});
}
}
})
// boot up the demo
var demo = new Vue({
el: '#demo',
data: {
treeData: data
}
})
body {
font-family: Menlo, Consolas, monospace;
color: #444;
}
.item {
cursor: pointer;
}
.folderTitleSpan:hover {
font-weight: bold;
border: 1px solid darkblue;
}
.folderTitleSpan:focus,
li span:nth-child(1):focus+.folderTitleSpan {
background-color: darkblue;
color: white;
}
.node,
.add {
list-style-type: none;
padding-left: 10px !important;
}
.folderChevronSpan::before {
color: #444;
content: '\25b6';
font-size: 10px;
margin-left: -1em;
position: absolute;
transition: -webkit-transform .1s ease;
transition: transform .1s ease;
transition: transform .1s ease, -webkit-transform .1s ease;
-webkit-transition: -webkit-transform .1s ease;
}
.folderChevronSpan.opened::before {
transform: rotate(90deg);
-webkit-transform: rotate(90deg);
}
ul {
padding-left: 1em;
line-height: 1.5em;
list-style-type: dot;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17-beta.0/vue.js"></script>
<!-- item template -->
<script type="text/x-template" id="item-template">
<li>
<span :class="setChevronClass" tabindex="0" ref="toggler" @click="toggle">
</span>
<span @click="selectNode" tabindex="1" :class="{folderTitleSpan: isFolder}">
{{ model.name }}
</span>
<span v-if="isFolder">[{{ open ? '-' : '+' }}]</span>
<ul v-show="open" v-if="isFolder">
<item class="item node" v-for="(model, index) in model.children" :key="index" :model="model">
</item>
<li class="add" @click="addChild">+</li>
</ul>
</li>
</script>
<p>(You can double click on an item to turn it into a folder.)</p>
<!-- the demo root element -->
<ul id="demo">
<item class="item node" :model="treeData">
</item>
</ul>