【问题标题】:Vue Calling function of the child component when rendering the child component in v-ifv-if中渲染子组件时子组件的vue调用函数
【发布时间】:2019-07-22 10:50:17
【问题描述】:

我想调用子组件的方法。
我认为开发人员使用$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>

当我尝试调用 showChild() 中子组件的方法 callFunction() 时,会引发错误。

未捕获的类型错误:无法读取未定义的属性“callFunction”

我认为原因是因为它在渲染子组件之前调用了子组件的函数。
我该如何解决这个问题? 谢谢。

【问题讨论】:

    标签: javascript vue.js vue-component


    【解决方案1】:

    如问题所述,$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,它将改为返回一个承诺。如果您愿意,这允许它与 async/await 一起使用:

    async showChild () {
      this.if_child = !this.if_child;
    
      await this.$nextTick();
    
      const child = this.$refs.child;
    
      if (child) {
        child.callFunction();
      }
    }
    

    【讨论】:

    • 我认为$nextTick() 只能用于mounted 钩子函数。谢谢。
    【解决方案2】:

    为什么它不起作用?

    因为当您的v-if 处于false 状态时,您的子组件不存在。 Vue 还没有创建它,所以你的 ref 子仍然是未定义的,这意味着 callFunction 不会被执行 (undefined)

    使用 Vue.nextTick API 怎么样?

    我尝试在代码上实现它(我尝试了同步和异步语法),但它仅在第一次尝试时有效,然后子 ref 再次变为 undefined ...这是因为组件被破坏了(之后if_child 转向 false) 所以‘ref’将是‘undefined’。

    我该如何解决这个问题?

    我找到了两种方法可以解决您的问题:

    1 - 通过在您的孩子上使用v-show 而不是v-if ...这将使您的孩子始终可用(始终呈现以便始终定义您的ref),display : none 处于 false 状态;

    2 - 但是,如果您坚持使用v-if,您可以添加另一个变量,当 DOM 完成渲染(使用 nextTick API)时该变量将发生变化......并且您的子组件将监视该变量并在该变量上执行函数...您可以这样做:

    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;
    }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
    <div id="app">
      <div v-if="if_child">
        <child id="child" class="child" :exe="executeTheChildFunction"></child>
      </div>
      <button type="button" @click="showChild">
        Toggle Child
      </button>
    </div>

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-05-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-12-03
      • 1970-01-01
      • 2019-02-14
      • 2020-01-21
      相关资源
      最近更新 更多