今天突然想总结下vue组件之间的交互方法,于是边写case边整理
交互方式一:使用props 和 $emit
【解析】父组件通过v-on绑定一个属性向子组件传递数据,子组件通过props接收父组件的数据;
子组件通过$emit向父组件发送一个事件,父组件通过子组件发送的自定义事件进行接收子组件传递过来的数据。
vm.$emit( “事件名”, 参数)
代码如下:
<!-- 父组件 Parent.vue-->
<div class="bigBox">
<div class="bigBox_left">
<h3>Parent</h3>
<div>Child Data==> {{childMsg}}</div>
</div>
<Child1 class="bigBox_right" :msg="msg" @sendData="getChildData"></Child1>
</div>
<script type='text/ecmascript-6'>
import Child1 from '@/views/components/Child1';
export default {
components: {
Child1,
},
data() {
return {
msg:"I'm your parent",
childMsg:'',
};
},
mounted() {},
methods: {
//子组件通过$emit发送了sendData事件,父组件通过自定义事件接收子组件发送的数据
getChildData(data) {
this.childMsg = data;
}
}
}
</script>
<template>
<div class="child1_container">
<h3>Child</h3>
<!-- 子组件 Child.vue -->
<div>{{msg}}</div>
<button @click="sendData">发送数据</button>
</div>
</template>
<script type='text/ecmascript-6'>
export default {
components: {},
props:{
msg:{
type:String,
default:()=>{
return ''
}
}
},
data() {
return {
childMsg:"I'm your child"
};
},
mounted() {},
methods: {
sendData(){
this.$emit('sendData',this.childMsg)
}
}
}
</script>
执行代码效果图如下:
交互方式二:$ref
【解析】父组件通过在使用子组件的便签上使用ref="refName"属性,并且通过vue.$refs.refName来获取整个子组件定义的的属性和方法
【知识点】:①this.$options.data() //获取本组件初始化数据
代码如下:
⒈父组件代码
<!-- 父组件 Parent.vue-->
<div class="bigBox">
<div class="bigBox_left">
<h3>Parent</h3>
</div>
<Child1 class="bigBox_right" ref="childData"></Child1>
</div>
<script type='text/ecmascript-6'>
import Child1 from '@/views/components/Child1';
export default {
components: {
Child1,
},
data() {
return {
p_data:'11',
p_data2:'22'
};
},
mounted() {
console.log('本组件初始数据=>',this.$options.data())
console.log('子组件的属性和方法==>',this.$refs.childData);
console.log('子组件的初始数据==>',this.$refs.childData.$options.data());
this.$refs.childData.getMessage('Hello World');
this.$refs.childData.getParentData({name:'Mumu',sex:'male'});
},
methods: {
}
}
</script>
⒉子组件的数据
<div class="child1_container">
<h3>Child</h3>
<!-- 子组件 Child.vue -->
<p>父组件传过来的数据=>{{message}}</br>{{pdata}}</p>
</div>
<script type='text/ecmascript-6'>
export default {
components: {},
data() {
return {
message:'',
pdata:null,
};
},
mounted() {
},
methods: {
getMessage(parms){
this.message = parms;
},
getParentData(data){
this.pdata = JSON.stringify(data);
},
}
}
</script>
实现效果:
控制台打印的数据展示:
以上总结:
1)如果ref用在子组件上,指向的是组件实例,可以理解为对子组件的索引,通过$ref可以获取到在子组件里定义的属性和方法。
2)如果ref在普通的 DOM 元素上使用,引用指向的就是 DOM 元素,通过$ref可以获取到该DOM 的属性集合,轻松访问到DOM元素,作用与JQ选择器类似。
3)ref和props的区别:
①prop 着重于数据的传递,它并不能调用子组件里的属性和方法。比如创建类似于文章的组件时,自定义标题和内容这样的使用场景,最适合使用prop。
②$ref 着重于索引,主要用来调用子组件里的属性和方法,它并不擅长数据传递。而且ref用在dom元素的时候,能起到选择器的作用,这个功能比作为索引更常用到。
交互方式三:$children和$parent
【解析】父组件可以通过$children来获取子组件定义的属性和方法,拿到的是一个数组,可以通过 $children[i].paramsName 来获取某个子组件的属性值或函数
同样的,子组件也可以通过$parent来获取直接父亲组件定义的属性和方法。
代码如下:
⒈父组件
<!-- 父组件 Parent.vue-->
<div class="bigBox">
<div class="bigBox_left">
<h3>Parent</h3>
<div class="chi1_data">
<p>Child-1的数据=></p>
<div>{{child1_data}}</div>
</div>
<div class="chi2_data">
<p>Child-2的数据=></p>
<div>{{child2_data}}</div>
</div>
</div>
<Child1 class="bigBox_right1"></Child1>
<Child2 class="bigBox_right2"></Child2>
</div>
<script type='text/ecmascript-6'>
import Child1 from '@/views/components/Child1';
import Child2 from '@/views/components/Child2';
export default {
components: {
Child1,
Child2
},
data() {
return {
p_1:'Parent',
child1_data:null,
child2_data:null,
};
},
mounted() {
console.log('Children==>',this.$children);
console.log('Child-1==>',this.$children[0].$options.data());
},
methods: {
update(child){
switch(child){
case 'Child1':
console.log('Form->Child1==>',this.$children[0].ch1_form);
this.child1_data = JSON.stringify(this.$children[0].ch1_form);
return;
case 'Child2':
console.log('Form->Child2==>',this.$children[1].ch2_form);
this.child2_data = JSON.stringify(this.$children[1].ch2_form);
return;
default:
return;
}
}
}
}
</script>
⒉子组件Child1.vue
<template>
<div class="child1_container">
<h3>Child-1</h3>
<!-- 子组件 Child1.vue -->
<form>
<input type="text" v-model="ch1_form.name" class="c1_name" placeholder="姓名" value=""></br></br>
<input type="text" v-model="ch1_form.mobile" class="c1_mobile" placeholder="手机" value=""></br></br>
<input type="submit" @click="submit" value="提交">
</form>
</div>
</template>
<script type='text/ecmascript-6'>
export default {
components: {},
data() {
return {
ch1_1:'Child-1',
ch1_form:{
name:'Child-1',
mobile:'18888888888'
},
};
},
mounted() {
// console.log("child1->parent==>",this.$parent);
},
methods: {
submit(){
//把本组件的数据发送到父组件
this.$parent.update('Child1');
}
}
}
</script>
⒊子组件Child2.vue
<template>
<div>
<h3>Child-2</h3>
<!-- 子组件 Child2.vue -->
<form>
<input type="text" v-model="ch2_form.name" class="c1_name" placeholder="姓名" value=""></br></br>
<input type="text" v-model="ch2_form.mobile" class="c1_mobile" placeholder="手机" value=""></br></br>
<input type="submit" @click="submit2" value="提交">
</form>
</div>
</template>
<script type='text/ecmascript-6'>
export default {
components: {},
data() {
return {
ch2_1:'Child-2',
ch2_form:{
name:'Child-2',
mobile:'199999999',
}
};
},
mounted() {
// console.log("child2->parent==>",this.$parent);
},
methods: {
submit2(){
//把本组件的数据发送到父组件
this.$parent.update('Child2');
}
}
}
</script>
效果展示:
控制台打印信息展示:
交互方式四:$attrs和$listeners
【问题描述】父组件A和子组件B之间的传值可以用props,但是如果父组件A想要和B组件的子组件C通信应该怎么传值呢?虽然可以通过父组件A先向子组件B组件通过props传值,再通过子组件B用props向B组件的子组件C传值,虽然这样能够实现,但是如果是A组件向B组件的子组件C的子组件D传值呢?如果C组件中的数据发生了变化,那么A组件如何能更新到变化之后的数据呢?
【解析】Vue2.4中引入了$attrs和$listeners,新增了inheritAttrs 选项
先来实现以上问题中,我们先来实现A向C传递数据
A组件
<!-- 父组件 Parent.vue-->
<div class="bigBox">
<div class="bigBox_left">
<h3>父组件A</h3>
</div>
<Child1 class="bigBox_right" :foo="foo" :coo="coo"></Child1>
</div>
<script type='text/ecmascript-6'>
import Child1 from '@/views/components/Child1';
export default {
components: {
Child1,
},
data() {
return {
foo:"Hello World",
coo:"Hello Licy",
};
},
mounted() {
},
methods: {
}
}
</script>
B组件
<template>
<div>
<h3>子组件Child1 B</h3>
<p>父组件数据foo=>{{foo}}</p>
<p>attrs=>{{$attrs}}</p>
<Child11 v-bind="$attrs"></Child11>
</div>
</template>
<script type='text/ecmascript-6'>
import Child11 from './Child11.vue';
export default {
components: {
Child11,
},
props:["foo"],
inheritAttrs:false,
data() {
return {
};
},
mounted() {
},
methods: {
}
}
</script>
C组件
<template>
<div>
<h3>Child1的子组件Child11 C</h3>
<!-- Child1 的子组件 -->
<p>coo==>{{coo}}</p>
</div>
</template>
<script type='text/ecmascript-6'>
export default {
components: {},
props:['coo'],
data() {
return {
sund:this.coo,
};
},
mounted() {},
methods: {
sendData(){
this.$emit('receiveData',this.sund);
}
}
}
</script>
在B组件中,如果不设置inheritAttrs:false,这个属性的话,则元素
A组件向C组件传递值COO,需要在B组件调用B组件的子组件的地方绑定$attrs,也就是
C组件接收的时候,同样也需要用props来声明,
<p>coo==>{{coo}}</p>然后直接取值就可以了
以上是实现A组件向子组件的子组件传递数据的过程,那么如果C组件中接收到的数据发生了改变,A组件又如何才能更新到呢?
A组件:
<!-- 父组件 Parent.vue-->
<div class="bigBox">
<div class="bigBox_left">
<h3>父组件A</h3>
<p>接收到的数据=>{{received}}</p>
</div>
<Child1 class="bigBox_right" :foo="foo" :coo="coo" @receiveData="receive"></Child1>
</div>
<script type='text/ecmascript-6'>
import Child1 from '@/views/components/Child1';
export default {
components: {
Child1,
},
data() {
return {
foo:"Hello World",
coo:"Hello Licy",
received:null,
};
},
mounted() {
},
methods: {
receive(data){
this.received = data;
}
}
}
</script>
B组件:
<template>
<div>
<h3>子组件Child1 B</h3>
<p>父组件数据foo=>{{foo}}</p>
<p>attrs=>{{$attrs}}</p>
<Child11 v-bind="$attrs" v-on="$listeners"></Child11>
</div>
</template>
<script type='text/ecmascript-6'>
import Child11 from './Child11.vue';
export default {
components: {
Child11,
},
props:["foo"],
inheritAttrs:false,
data() {
return {
};
},
mounted() {
},
methods: {
}
}
</script>
C组件:
<template>
<div>
<h3>Child1的子组件Child11 C</h3>
<!-- Child1 的子组件 -->
<p>coo==>{{coo}}</p>
<input type="text" v-model="sund">
<input type="submit" value="发送数据" @click="sendData">
</div>
</template>
<script type='text/ecmascript-6'>
export default {
components: {},
props:['coo'],
data() {
return {
sund:this.coo,
};
},
mounted() {},
methods: {
sendData(){
this.$emit('receiveData',this.sund);
}
}
}
</script>
以上代码,在C组件中用sund值来更新接收到的COO,通过$emit向A发送数据,在B组件中调用C组件的地方绑定了$listeners
<Child11 v-bind="$attrs" v-on="$listeners"></Child11>
在A组件中用自定义事件接收C组件的数据
<Child1 class="bigBox_right" :foo="foo" :coo="coo" @receiveData="receive"></Child1>
即可实现通信。
交互方式五:依赖注入
【问题描述】现在有一个父组件A,和子组件B,子组件C,子组件D...,甚至还有子组件B的子组件bb,子组件cc...,在某种情况下A的子组件或者孙子组件等想要访问A组件的一个方法getMsg();这种情境下就可以使用依赖注入,能够很好的解决这个问题。
【解析】
父组件:
<script>
export default {
components:{},
data(){
return {
msg:'我是父组件'
}
},
//父组件提供provide对外提供被访问的函数,子组件使用inject“导入”父组件的函数即可
provide(){
return {
getMsg:()=>{
return this.msg;
}
}
},
}
</script>
子组件的子组件的子组件(inject注入这个方法):
<script>
export default {
components:{},
data(){
return {
tittle:'我是子组件的子组件的子组件'
}
},
//
inject:['getMsg'],
computed:{
msg(){
return this.getMsg();
}
},
}
</script>