在实际页面中,很多时候页面一个部分的改变会导致另外一个部分的改变,比如在表格中输入数据会改变相邻的图表形状
但是实际上这两个部分大都是差异很大,所以开发中一般都是做成两个组件的。如果在一个大组件中把所有的内容都包含进去,这就不够结构化了,而且有些时候会导致组件特别大。所以最好还是在一个组件中调用另外一个组件的内部函数。
基本原理是
1. 在激发组件emit一个事件,比如表格输入数据的变化,emit时还可以附带改变的数据信息
2. 然后在父组件捕捉这个事件
3. 在父组件对应的捕捉函数中,通过
this.$refs['target-component'].targetFunction(param)
来使得目标组件的内部函数得到调用,而且连最初激发这个事件的附带信息也可以传递过来。
看一个样例代码
激发组件。通过在$emit中附加参数值,可以在发送事件的同时,附加一些其他的数据,这个数据可以是对象或者数组,以便提供更多的信息。也可以不带,这样父组件转发时也就没有附加参数。
<template>
<div ref="source-component" :style="computedStyle" @click="onClick">
<button value="test"></button>
</div>
</template>
<script>
export default {
methods:{
onClick(){
this.$emit('SourceClick', 'this is source data')
}
}
}
</script>
父组件。要注意的是
1. 在template中,对应事件的响应函数只能给函数名,不可以带括号或者参数值,只有这样才能保证从激发组件发送的事件中附带的参数得以传递。另外在父组件的转发事件的函数中,不需要event作为形参,直接把附加数据作为唯一的形参即可,若没有附加参数,则不需要形参。
2. 响应组件要通过$refs来直接指定,然后通过点操作符直接调用目标组件的内部函数即可。
3. 这个emit的事件不具有冒泡属性,所以不会向更远的父级传播,没必要stopPropagation(),所以捕捉时必须要在对应的子组件的标签上写
<template>
<div>
<sour @SourceClick="passParam"></sour>
<targ ref="target-component"></targ>
</div>
</template>
<script>
import Source from './Source.vue'
import Target from './Target.vue'
export default {
components:{
'sour': Source,
'targ': Target
}
methods:{
passParm(param){
console.log('this is response in parent component')
this.$refs['target-component'].response(param)
}
}
}
</script>
目标组件。响应函数和普通函数没有什么差别,必要时有形参。
<template>
<div :style="computedStyle">
<p>{{msg}}</p>
</div>
</template>
<script>
export default {
data(){
return {
msg:''
}
},
methods:{
response(pa){
this.msg=`this is target and ${pa}`
console.log('this is response in target component')
}
}
}
</script>
这是一个最基本的同级组件的调用,如果页面特别复杂,有很多级,就需要向更高的父级或者更低的子级传递调用即可。
可以在最近的父级的捕捉函数中继续emit事件,这样就能向更上一级传递事件。以此类推可以一直传递到必要的父级。
对子级的调用有两种方法,一种是通过多层$refs直接找到子级的对应组件,然后调用它的函数。另外一种是在子级的函数中通过$refs调用下一子级,这样就需要在每层子级都要有对应的回调函数。
通过组合,就可以调用到整个页面上任意位置的组件的函数了。