我想调用子组件的方法。
我认为开发人员使用$nextTick
函数来处理所有子组件呈现后的数据。
但是当通过v-if
指令进行渲染时,如何调用子组件的方法。
这是example。
var comp = Vue.component('child', {
data:function(){
return {
}
},
template:`
<div class="child">
I'm a child
</div>
`,
methods:{
callFunction:function(){
console.log("I'm called");
}
}
});
var vm = new Vue({
el:'#app',
data:{
if_child:false
},
methods:{
showChild(){
this.if_child = !this.if_child;
//Calling child's function
this.$refs.child.callFunction();
}
}
})
.child{
display:inline-block;
padding:10px;
background:#eaeaea;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<div v-if="if_child">
<child ref="child" class="child"></child>
</div>
<button type="button" @click="showChild">
Toggle Child
</button>
</div>
当我尝试调用callFunction()
中子组件的方法showChild()
时,将引发错误。
未捕获的TypeError:无法读取未定义的属性'callFunction'
我认为原因是因为它在呈现子组件之前调用了子组件的功能。
我该如何解决这个问题?
谢谢。
答案 0 :(得分:2)
为什么不起作用?
因为当您的v-if
位于false
上时,您的子组件不存在。 Vue尚未创建它,因此您的ref
子级仍未定义,这意味着callFunction
不会被执行(undefined
)
如何使用Vue.nextTick API?
我尝试在代码上实现它(我尝试了同步和异步语法),但是它仅在第一次尝试时起作用,然后子项ref
再次变为undefined
...我认为这是因为该组件被销毁,因此“ ref”将为“ undefined”
我该如何解决?
我发现了两种可以解决您的问题的方法:
1-通过在您的孩子上使用v-show
而不是v-if
...,这将使您的孩子始终可用(总是渲染,因此您的ref
总是会被定义),并带有{ {1}}处于错误状态; </ p>
2-但是,如果您坚持使用display : none
,则可以添加另一个变量,该变量将在DOM完成呈现时被更改(使用nextTick API)...您的子组件将监视该变量并执行该函数在此之上……这是您可以做到的:
v-if
Vue.component('child', {
props: ['exe'],
watch: {
exe() {
this.callFunction()
}
},
template: `
<div class="child">
I'm a child
</div>
`,
methods: {
callFunction: function() {
console.log("I'm called");
}
}
});
var vm = new Vue({
el: '#app',
data: {
if_child: false,
executeTheChildFunction: false,
},
methods: {
showChild() {
this.if_child = !this.if_child;
//Calling child's function
this.$nextTick(function() {
this.executeTheChildFunction = !this.executeTheChildFunction;
})
}
}
})
.child {
display: inline-block;
padding: 10px;
background: #eaeaea;
}
答案 1 :(得分:2)
如问题中所述,$nextTick
是这里的解决方案。
Vue一起批量渲染。当您更改反应性数据(例如if_child
)时,它不会立即导致任何渲染。而是将组件添加到需要渲染的组件列表中。完成所有数据更改后,Vue将呈现列表中的所有组件。
有两个原因。首先,渲染非常昂贵。其次,如果您正在更新数据,则数据可能处于不一致状态,无法正确呈现。
“渲染”这个名称有点误导。这听起来有点像画画。但是,它还包括创建和销毁子组件之类的事情。
$refs
会在组件渲染后立即更新。这一切都发生在下一个刻度线的开始。为了等待,我们使用$nextTick
。
Vue.component('child', {
template: `
<div class="child">
I'm a child
</div>
`,
methods: {
callFunction () {
console.log("I'm called");
}
}
});
var vm = new Vue({
el: '#app',
data: {
if_child: false
},
methods: {
showChild () {
this.if_child = !this.if_child;
this.$nextTick(() => {
const child = this.$refs.child;
if (child) {
child.callFunction();
}
});
}
}
});
.child {
display: inline-block;
padding: 10px;
background: #eaeaea;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<div v-if="if_child">
<child ref="child" class="child"></child>
</div>
<button type="button" @click="showChild">
Toggle Child
</button>
</div>
这是关键部分:
showChild () {
this.if_child = !this.if_child;
this.$nextTick(() => {
const child = this.$refs.child;
if (child) {
child.callFunction();
}
});
}
您可能想知道为什么它需要if (child) {
。这是因为该按钮可切换if_child
的值。方法名称showChild
实际上是误导的。第一次单击该按钮将创建该子项,但是下次单击该子项将被销毁。
如果您没有将回调传递给$nextTick
,它将返回一个Promise。如果愿意,可以将其与async
/ await
一起使用:
async showChild () {
this.if_child = !this.if_child;
await this.$nextTick();
const child = this.$refs.child;
if (child) {
child.callFunction();
}
}