让我们说我有一个父组件Tabs,它把子Tab组件作为插槽。
因此设置如下:
标签(父母)
<div>
<slot name="tabChild">
</div>
标签(儿童)
<div>
Tab {{name}}
</div>
MyApp
<Tabs>
<Tab slot="tabChild" name="1" ></Tab>
<Tab slot="tabChild" name="1" ></Tab>
</Tabs>
但是,当我尝试以编程方式访问其子级时,在Tabs(父级)组件中,如下所示:
标签组件
mounted(){
let childTabs = this.$children //this is empty??
childTabs = this.$slots //this is correctly the child Tab Components
}
此外,在Tab(子)组件中,当我尝试访问其父级(我认为它是Tabs组件)(因为它们已插入其中)时,不是:
标签组件
mounted(){
let parentTab = this.$parent //this is MyApp (grandfather), NOT Tabs
}
为什么在较大的Tabs组件中插入的tab子组件不是其子组件?
答案 0 :(得分:0)
好吧,$parent
将始终引用嵌套在其中的特定组件的“直接”父级/包装器,因此当需要引用“根”级父级时,它并不十分可靠。
以下是官方文档的一些摘录:
在大多数情况下,进入父级会使您的应用程序更难以调试和理解,尤其是当您更改父级中的数据时。以后查看该组件时,将很难弄清楚该突变来自何处。 [1]
请谨慎使用$parent
和$children
,因为它们主要用作逃生舱口。首选使用道具和事件进行亲子沟通。 [2]
隐式的亲子交流:亲子组件交流应首选道具和事件,而不是this.$parent
或变异道具。
理想的Vue应用程序是道具下降,事件发生。遵循此约定可使您的组件更容易理解。 [3]
不幸的是,使用$parent
属性无法很好地扩展嵌套更深的组件。在此处使用两个新的实例选项:provide
和inject
,依赖注入就很有用。 [4]
下面是一个简单的示例,它演示了上述建议:
const Parent = Vue.extend({
template: `
<ul :style="{ columnCount: colCount }">
<slot></slot>
</ul>
`,
provide() {
return {
biologicalParent: this
}
},
props: ['value', 'colCount', 'message'],
methods: {
sayIt() {
const
num = this.$children.indexOf(this.value) + 1,
message = [
`I am child no. ${num}`,
`among ${this.$children.length} of my siblings`,
`in ${this.colCount} different lineages.`
]
.join(' ');
this.$emit('update:message', message);
}
},
watch: {
value: 'sayIt'
}
});
const Child = Vue.extend({
template: `<li v-text="name" @click="setChild"></li>`,
props: ['name'],
inject: ['biologicalParent'],
methods: {
setChild() {
this.biologicalParent.$emit('input', this);
}
}
});
new Vue({
el: '#demo',
data: () => ({
lineage: 3,
childCount: 10,
message: 'Click on a child for the associated message.',
lastChild: undefined
}),
components: {
Parent,
Child
}
});
input {
width: 4em;
}
li {
cursor: pointer;
}
.message {
background-color: beige;
border: 1px solid orange;
padding: 3px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="demo">
<table>
<tr>
<td>Child count:</td>
<td><input type="number" v-model="childCount" /></td>
</tr>
<tr>
<td>Lineage:</td>
<td><input type="number" v-model="lineage" /></td>
</tr>
</table>
<parent
v-model="lastChild"
:col-count="lineage"
:message.sync="message">
<child
v-for="(n, i) of Array.apply(null, {length: childCount})"
:key="i"
:name="`child #${i+1}`">
</child>
</parent>
<p class="message">{{ message }}</p>
</div>
provide
选项允许我们指定要提供作为后代组件的data
或methods
。在上面的示例中,这是Parent
实例。
注意如何在运行时(单击时)而不是编译时(渲染阶段)评估Child
索引/编号。