我一直感觉搞懂父子组件互相调用方法和传值,你就会vue,用了这么久还不会,最近就需求需要刚刚学会了几种方法

[doc]

方案一:通过ref直接调用子组件的方法;

父组件中

<template>
    <div>
        <Button @click="handleClick">点击调用子组件方法</Button>
        <Child ref="child"/>
    </div>
</template>  
<script>
import Child from './child';
export default {
    methods: {
        handleClick() {
              this.$refs.child.sing('111');
		// 如果有显示隐藏页面时候就使用nextTick
		/**
		this.$nextTick(() => {
        		this.$refs.basLocationChildRef.getLocationById(row.id)
      		})
		*/
        },
    },
}
</script>

子组件

<template>
  <div>我是子组件</div>
</template>
<script>
export default {
  methods: {
	// ret 是父组件带来的参数
    sing(ret) {
      console.log('我是子组件的方法'+ret);
    },
  },
};
</script>

方案二:onon和emit调用子组件的方法;

首先我们要了解onon和emit

vm.on(event,callback):监听当前实例上的自定义事件。事件可以由vm.on( event, callback ):监听当前实例上的自定义事件。事件可以由vm.emit触发。回调函数会接收所有传入事件触发函数的额外参数。

vm.$emit( event, […args] ):触发当前实例上的事件。附加参数都会传给监听器回调。
父组件

<template>
    <div>
        <div @click="click">点击父组件</div>
        <child ref="child"></child>
    </div>
</template>

<script>
    import child from "./child";
    export default {
        methods: {
            click() {
                this.$refs.child.$emit('childMethod','发送给方法一的数据') // 方法1:触发监听事件
                this.$refs.child.callMethod() // 方法2:直接调用
            },
        },
        components: {
            child,
        }
    }
</script>

子组件

<template>
    <div>子组件</div>
</template>

<script>
    export default {
        mounted() {
            this.monitoring() // 注册监听事件
        },
        methods: {
            monitoring() { // 监听事件
                this.$on('childMethod', (res) => {
                    console.log('方法1:触发监听事件监听成功')
                    console.log(res)
                })
            },
            callMethod() {
                console.log('方法2:直接调用调用成功')
            },
        }
    }
</script>

方案三:父组件传递数据给子组件

父组件:

<parent>
    <child :child-msg="msg"></child>  //这里必须要用 - 代替驼峰
</parent>

data(){
    return {
        msg: [1,2,3]
    };
}

子组件通过props来接收数据:

方式1:

props: ['childMsg']

方式2:

props: {
    childMsg: Array //这样可以指定传入的类型,如果类型不对,会警告
}

方式3:

props: {
    childMsg: {
        type: Array,    //传入的类型
        default: [0,0,0] //这样可以指定默认的值
    }
}

props参数

props除了数组,也可以是一个对象,此时对象的键对应的props的名称,值又是一个对象,可以包含如下属性

  • type: ;类型,可以设置为:String、Number、Boolean、Array、Object、Date等等 ;如果只设置type而未设置其他选项,则值可以直接用类型,例如:props:
  • default ;默认值
  • required ;布尔类型,表示是否必填项目
  • validator ;自定义验证函数

方案四:子组件与父组件通信

子组件:

<template>
    <div @click="testClick"></div>
</template>
methods: {
    testClick() {
        this.$emit('test','123'); //$emit(even,value)even 是一个函数,value 是传给父组件的值      , 触发名为test方法, '123'为向父组件传递的数据
    }
}

父组件接收:

<div>
 //监听子组件触发的test事件,然后调用change方法
    <child @test="change" :msg="msg"></child> 
</div>
methods: {
    change(val) {
        this.msg = val;  // val: 123
    }
}

方案五:非父子组件通信1

如果2个组件不是父子组件那么如何通信呢?这时可以通过eventHub来实现通信.
所谓eventHub就是创建一个事件中心,相当于中转站,可以用它来传递事件和接收事件.
let Hub = new Vue(); //创建事件中心

组件1触发

<div @click="eve"></div>

methods: {
    eve() {
        Hub.$emit('change','hehe'); //Hub触发事件
    }
}

组件2接收:

<div></div>

created() {
    Hub.$on('change', () => { //Hub接收事件
        this.msg = 'hehe';
    });
}

方案六:非父子组件通信2

父组件

<template>
	<div>
		<div v-if="!userShow">
			父组件内容区
			<el-button @click="lookUserInfo(scope.row)">&nbsp;查看</el-button> 
		</div>
		<!-- 子组件 -->
		<user-manager  v-if="userShow"  @close="showUserInfo" ref="child"> </user-manager>	
	</div>
</template>
<script>
	//导入用户页面
	import userManager from '../userManager.vue';
	export default {
	 	name:'taskManager',
	 	components:{userManager},
	 	data() {
	 		return {			
				userShow:false,				
			}
		},
		methods: {
			//显示子组件,隐藏父组件
			lookUserInfo(row) {
				this.userShow = true;
				this.$refs.child.chlidMethods
			},
			//此方法,子组件会调用,调用返回父页面:隐藏子组件,显示父组件
			showUserInfo() {
				this.userShow = false;
			},
		}
	}	
</script>

子组件

<template>
	<div>
		<!-- 返回父页面按钮 -->
		<div>
            <el-button @click="goToParent"> &nbsp;&nbsp;返回</el-button>
        </div>
		<div class="white-bg margin auto">
			<el-table>
				数据表格展示区	
			</el-table>
		</div>
	</div>
</template>
<script>
	export default {
	 	name:'userManager',
	 	data() {
	 		return {	
			}
		},	
		methods: {
			goToParent() {
				//调父页面方法
			    this.$emit('close');
			}
			chlidMethods() {
				console.log("父组件调子组件方法了")
			}
		}
	}	
</script>

七、其他父子案例

  • 步骤一、父页面子标签写一个属性

image.png

  • 步骤二、数据这边定义一个假如随时改变的值
data() {
    return {
      activeName: 'second',
      param: 'DB2',
      myParm: 'MySQl'
    }
  },
  • 步骤三、这边就是父标签的随意改变的值
handleClick(tab, event) {
      if (tab.name === '0') {
        this.param = 'DB2'
      } else if (tab.name === '1') {
        this.param = 'MySQL'
      } else if (tab.name === '2') {
        this.param = 'SQL SERVER'
      } else if (tab.name === '3') {
        this.param = 'DB1'
      }
      console.log('点击事件-->' + this.param)
    }

子页面

  • 动态取值,使用 watch:{} 函数
watch: {
    param: {
      handler(newValue, oldValue) {
        this.param = newValue
        console.log('ServerBtn页面' + '新值' + newValue + '老值' + oldValue + 'param' + this.param)
        this.initBtn()
      },
      deep: true
    }
  },
  • 子组件取值,使用 props 来取
  // 接收父组件值
  props: {
    param: {
      type: String,
      default: 'MySQL'
    }
  },

十、父组件给子组件的子组件操作

  • 父组件
<NodeAccessTable ref="nodeAccessTable" />

<el-button v-if="hasPermission"
 size="mini" @click="$refs.nodeAccessTable.$refs.allPro.show = true" >
	<svg-icon class="drag-handler" icon-class="zongbian" />
     设置
</el-button>
  • 子组件
<all-project-no-set-modal ref="allPro" :category-arr="categoryArr" :category-id="categoryId" />
  • 子组件中子组件
<el-dialog
    v-el-drag-dialog
    class="dialogBox"
    :close-on-click-modal="false"
    :title="!operate ? '设置' 
    :visible.sync="show"
    width="60%"
    :before-close="closeDialog"
  >
  </el-dialog>

九、子组件接收值类型

String			字符串
Number			数字
Boolean			判断
Array			数组
Object			对象