如何使用带 Vue.js 个插槽的条件渲染?
How to use conditional rendering with Vue.js slots?
如何使用 v-if
的结果在 Vue 中渲染两个不同的组件?如果重要的话,我也尝试在使用 v-for
渲染 TreeView
时执行此操作。到目前为止,这是我尝试过的。
TreeView.vue:
<template>
<span>
<ul v-show="isOpen" v-if="isFolder">
<p
v-for="(child, index) in item.children"
v-bind:item="child"
v-bind:key="index"
<span v-if="!child.isFolder">
<slot v-bind:individualBookmark="child"></slot>
</span>
<span v-else>
<div v-bind:class="{bold: isFolder}" v-on:click="toggle" v-on:dblclick="makeFolder" v-on:contextmenu="rightClick">
{{ child.name }}
<span v-if="isFolder">[{{ isOpen ? '-' : '+' }}]</span>
</div>
</span>
</p>
</ul>
</span>
</template>
<script>
export default {
name: "TreeView",
props: {
item: Object
},
components: {
},
data: function() {
return {
isOpen: false
}
},
computed: {
isFolder: function() {
return this.item.children.length > 0;
//return this.item.children && this.item.children.length;
}
},
methods: {
toggle: function() {
if (this.isFolder) {
this.isOpen = !this.isOpen;
}
},
makeFolder: function() {
if (!this.isFolder) {
this.$emit("make-folder", this.item);
this.isOpen = true;
}
},
rightClick: function() {
alert("Right click action")
}
}
}
</script>
App.vue
(Bookmark
标签是我构建的自定义组件,没有 isFolder
计算 属性):
<template>
<div id="app">
<TreeView v-slot:default="slotProps"
v-bind:item="treeData"
v-on:make-folder="makeFolder"
v-on:add-item="addItem">
<Bookmark v-bind="slotProps.individualBookmark"></Bookmark>
</TreeView>
</div>
</template>
<script>
import Bookmark from './components/Bookmark.vue'
import TreeView from './components/TreeView.vue'
import Vue from 'vue'
export default {
name: 'App',
components: {
Bookmark,
TreeView
},
data: function() {
return {
treeData : {
name: "My Tree",
children: [
{ name: "hello" },
{ name: "wat" },
{
name: "child folder 1",
children: [
{
name: "child folder",
children: [{ name: "hello" }, { name: "wat" }]
},
{ name: "hello" },
{ name: "wat" },
{
name: "child folder",
children: [{ name: "hello" }, { name: "wat" }]
}
]
}
]
}
}
},
methods: {
makeFolder: function(item) {
Vue.set(item, "children", []);
this.addItem(item);
},
addItem: function(item) {
item.children.push({
name: "new stuff"
});
}
}
}
</script>
当我 运行 这样做时,出于某种原因,TreeView.vue 中的 v-if="!child.isFolder"
始终计算为 true,因此它呈现 Bookmark 组件。即使在 v-if
应该评估为 false 的情况下,如给定 treeData
的“子文件夹 1”子对象时,它仍然评估为 true。我感觉问题与我在 TreeView.vue
中使用 <slot></slot>
的方式有关,但我不确定。为什么 v-if
总是评估为 true 而从不为 false?
问题也可能与我如何编写 isFolder
属性.
有关
在 Treeview
组件内添加一个名为 computedChildren
的计算 属性,它通过添加 isFolder
属性 映射项目道具:
computed: {
isFolder: function() {
return this.item.children.length > 0;
//return this.item.children && this.item.children.length;
},
computedChildren(){
return this.item.children.map(child=>{
child.isFolder=child.children?child.children.length>0:false //this add the property isFolder
return child
})
}
},
然后按如下方式循环:
<p
v-for="(child, index) in computedChildren"
...
要替换插槽,您可以使用 template
元素:
<TreeView
v-bind:item="treeData"
v-on:make-folder="makeFolder"
v-on:add-item="addItem">
<template v-slot:default="slotProps">
<Bookmark v-bind="slotProps.individualBookmark"></Bookmark>
</template>
</TreeView>
如何使用 v-if
的结果在 Vue 中渲染两个不同的组件?如果重要的话,我也尝试在使用 v-for
渲染 TreeView
时执行此操作。到目前为止,这是我尝试过的。
TreeView.vue:
<template>
<span>
<ul v-show="isOpen" v-if="isFolder">
<p
v-for="(child, index) in item.children"
v-bind:item="child"
v-bind:key="index"
<span v-if="!child.isFolder">
<slot v-bind:individualBookmark="child"></slot>
</span>
<span v-else>
<div v-bind:class="{bold: isFolder}" v-on:click="toggle" v-on:dblclick="makeFolder" v-on:contextmenu="rightClick">
{{ child.name }}
<span v-if="isFolder">[{{ isOpen ? '-' : '+' }}]</span>
</div>
</span>
</p>
</ul>
</span>
</template>
<script>
export default {
name: "TreeView",
props: {
item: Object
},
components: {
},
data: function() {
return {
isOpen: false
}
},
computed: {
isFolder: function() {
return this.item.children.length > 0;
//return this.item.children && this.item.children.length;
}
},
methods: {
toggle: function() {
if (this.isFolder) {
this.isOpen = !this.isOpen;
}
},
makeFolder: function() {
if (!this.isFolder) {
this.$emit("make-folder", this.item);
this.isOpen = true;
}
},
rightClick: function() {
alert("Right click action")
}
}
}
</script>
App.vue
(Bookmark
标签是我构建的自定义组件,没有 isFolder
计算 属性):
<template>
<div id="app">
<TreeView v-slot:default="slotProps"
v-bind:item="treeData"
v-on:make-folder="makeFolder"
v-on:add-item="addItem">
<Bookmark v-bind="slotProps.individualBookmark"></Bookmark>
</TreeView>
</div>
</template>
<script>
import Bookmark from './components/Bookmark.vue'
import TreeView from './components/TreeView.vue'
import Vue from 'vue'
export default {
name: 'App',
components: {
Bookmark,
TreeView
},
data: function() {
return {
treeData : {
name: "My Tree",
children: [
{ name: "hello" },
{ name: "wat" },
{
name: "child folder 1",
children: [
{
name: "child folder",
children: [{ name: "hello" }, { name: "wat" }]
},
{ name: "hello" },
{ name: "wat" },
{
name: "child folder",
children: [{ name: "hello" }, { name: "wat" }]
}
]
}
]
}
}
},
methods: {
makeFolder: function(item) {
Vue.set(item, "children", []);
this.addItem(item);
},
addItem: function(item) {
item.children.push({
name: "new stuff"
});
}
}
}
</script>
当我 运行 这样做时,出于某种原因,TreeView.vue 中的 v-if="!child.isFolder"
始终计算为 true,因此它呈现 Bookmark 组件。即使在 v-if
应该评估为 false 的情况下,如给定 treeData
的“子文件夹 1”子对象时,它仍然评估为 true。我感觉问题与我在 TreeView.vue
中使用 <slot></slot>
的方式有关,但我不确定。为什么 v-if
总是评估为 true 而从不为 false?
问题也可能与我如何编写 isFolder
属性.
在 Treeview
组件内添加一个名为 computedChildren
的计算 属性,它通过添加 isFolder
属性 映射项目道具:
computed: {
isFolder: function() {
return this.item.children.length > 0;
//return this.item.children && this.item.children.length;
},
computedChildren(){
return this.item.children.map(child=>{
child.isFolder=child.children?child.children.length>0:false //this add the property isFolder
return child
})
}
},
然后按如下方式循环:
<p
v-for="(child, index) in computedChildren"
...
要替换插槽,您可以使用 template
元素:
<TreeView
v-bind:item="treeData"
v-on:make-folder="makeFolder"
v-on:add-item="addItem">
<template v-slot:default="slotProps">
<Bookmark v-bind="slotProps.individualBookmark"></Bookmark>
</template>
</TreeView>