vue2祖辈组件怎么调用孙辈组件的方法?

192 阅读1分钟

需求

‘保存’按钮在祖辈组件中, 孙辈组件有表单数据,点击保存按钮需要先校验表单数据,校验通过才能过走后续的逻辑。

问题

校验方法是在孙辈组件中写的,祖辈组件在保存是需要调用孙辈组件的方法?

解决

祖孙组件的通信方法:

  • attrsattrs和listeners
  • emitemit和on
  • provide 和 inject
  • 中央事件总线$eventBus

最终选择的是中央事件总线$eventBus

首先需要创建事件总线并将其导出,以便其它模块可以使用或者监听它。创建一个 .js 文件,比如 eventBus.js

其次组件中使用emitemit和on方法

发布事件$emit-传递值-祖辈组件

import EventBus from '@eventBus.js'

methods:{
  //点击保存按钮
  handleClickSave(){
    EventBus(this).$emit('validateElementForm',()=>{
      // callback 
      this.save()
    })
  },
  //验证通过后续操作
  save(){
    //...
    if(!this.save){
      this.$message.confirm('确定提交吗?', '提示', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning',
      }).then(() => {
        //接口请求
        console.log('确定保存')
      })
        .catch(() => {
          console.log('取消保存')
        });
    }
  }
}

收(订阅)事件$on-接收值-孙辈组件

import EventBus from '@eventBus.js'

//需要初始化的时候接收事件
created(){
  //接收事件
  EventBus(this).$on('validateElementForm',(callback)=>{
    //验证通过就callback
    //验证不通过就不调callback
    //验证不通过就不调callback
    if(this.validateForm()){
      callback && callback()
    }
  })
},
beforeDestory(){
    EventBus(this).$off('validateElementForm')
},
methods:{
  validateForm(){
    let flag = true
    this.$refs.formRef.validate((valid =>{
      flag = valid
      if(!valid){
        this.$message.warning('表单有未填写数据')
      }
    })
    return flag;
  }
}


后续问题

自测的时候又发现个问题,孙辈组件,条件不满足的时候是不做展示的,有进行v-if的判断,此时eventBus.$emit (‘valid’)就不会触发。

怎么判断eventBus是否有valid事件呀?

解决:将孙辈组件v-if判断的showFlag条件通过$emit传给父辈组件

data(){
    return{
        showFlag:false
    }
},

//=====修改保存方法=====
methods:{
    //记录孙辈组件是否显示
   recordShowFlag(flag){
        this.showFlag = flag
   },
  //点击保存按钮需要进行判断
  handleClickSave(){
      const that = this
      if(that.showFlag){
          EventBus(that).$emit('validateElementForm',()=>{
              that.save()
        })
      }else{
          that.save()
      } 
  }
}

<FatherDiablogCom 
   @recordShowFlag="recordShowFlag"
/>

data(){
    return{
        showFlag:false
    }
},


created(){
    api().then(res=>{
        ...
        this.showFlag = true
        this.$emit('recordShowFlag',this.showFlag)
        
    })
},
beforeDestory(){
    this.showFlag = false
    this.$emit('recordShowFlag',this.showFlag)
}


//-------------
<ChildrenDiablogCom 
   v-if="showFlag"
/>

参考文献: