1.父传子
父->子
-
props父子 使用场景: 电商 (松耦合)
-
$parent 子抓父 使用场景: 通用组件(紧耦合)
<子 :自定义属性="父数据"></..> 子组件: 选项 props:['自定义属性'] props:{自定义属性:{type/default/required/...}} 展示: 子模板 {{自定义属性}} 注意: props是只读的 props命名: props: ['postTitle'] <xx post-title="hello!"></xx> 单向下行绑定: 父级 prop 的更新会向下流动到子组件中,但是反过来则不行 在 JavaScript 中对象和数组是通过引用传入的,所以对于一个数组或对象类型的 prop 来说,在子组件中改变这个对象或数组本身将会影响到父组件的状态
关系:
- App -> ChildA -> ChildC
- App -> ChildB
App.vue
- 通过v-bind绑定要传过去的自定义属性
<template>
<div id="app">
<h3>app</h3>
<ChildA :msgApp="msgapp"></ChildA>
<ChildB></ChildB>
</div>
</template>
<script>
import ChildA from './components/ChildA'
import ChildB from './components/ChildB'
export default {
name:'app',
data(){
return{
msgapp:'app数据'
}
},
components:{
ChildA,ChildB
},
methods:{
show(){console.log('app_show')}
}
}
</script>
<style>
</style>
ChildA.vue
- 用props来接收自定义属性
- 可以将接收过来的值依次传给它的子
<template>
<div class='child-a'>
<h3>child-a</h3>
<ChildC :msgA="msga" :msg_App="msgApp"></ChildC>
</div>
</template>
<script>
import ChildC from './ChildC'
export default{
data(){
return{
msga:'child-a的数据'
}
},
props:['msgApp'],
components:{
ChildC
}
}
</script>
<style>
.child-a{
background:blue;
}
</style>
ChildC.vue
<template>
<div class='child-c'>
<h3>child-c</h3>
{{msg_App}}/{{msgA}}/{{msgc}}
</div>
</template>
<script>
export default{
data(){
return{
msgc:'child-c的数据'
}
},
props:['msgA','msg_App']
}
</script>
<style>
.child-c{
background:yellow;
}
</style>
ChildB.vue
- 直接通过this.$parent来抓取父的值,其中this可以省略
- 同时还可以利用this.$parent来调用父的方法
<template>
<div class='child-b'>
<h3>child-b</h3>
{{this.$parent.msgapp}}
</div>
</template>
<script>
export default{
data(){
return{
msgb:'child-b的数据'
}
},
mounted(){
console.log(this.$parent)
console.log('this可以省略,parent指向父',this.$parent.msgapp)
//调用父的方法
this.$parent.show()
}
}
</script>
<style>
.child-b{
background:green;
}
</style>
2.子传父
子->父
-
自定义事件$emit 使用场景: 电商 (松耦合)
-
$ ref 引用dom元素/$children 父抓子 使用场景: 通用组件(紧耦合)
子->父 事件(自定义) <子 @自定义事件="父方法"></..> 子: this.$emit('自定义事件',子.数据名) 父: methods-> 父方法(接受数据){处理} 始终使用 kebab-case 的事件名 父子之间共享数据和方法 <子 ref="自定义子名称"></..> 父访问子: this.$refs.自定义子名称.数据名/方法() 子访问父: this.$parent.数据名/方法() $refs 只会在组件渲染完成之后生效,并且它们不是响应式的,避免在模板或计算属性中访问 $refs
关系:
- App -> ChildA -> ChildC
- App -> ChildB
ChildA.vue
- 父中写一个自定义事件,同时还要在data里面自定义一个数据,便于拿取子中用$emit传过来的值
<template>
<div class='child-a'>
<h3>child-a</h3>
{{msg_c}}
<ChildC @send_childc="updateChildC"></ChildC>
</div>
</template>
<script>
import ChildC from './ChildC'
export default{
data(){
return{
msga:'child-a的数据',
msg_c:'-'
}
},
components:{
ChildC
},
methods:{
updateChildC(data){
console.log('ChildA收到了数据',data),
this.msg_c=data
}
},
}
</script>
<style>
.child-a{
background:blue;
}
</style>
ChildC.vue
- 用$emit来接收自定义事件,并将data返回给父级
<template>
<div class='child-c'>
<h3>child-c</h3>
</div>
</template>
<script>
export default{
data(){
return{
msgc:'child-c的数据'
}
},
mounted(){
this.$emit('send_childc',this.msgc)
}
}
</script>
<style>
.child-c{
background:yellow;
}
</style>
App.vue
- this.$children可以直接在父中拿到子的数据,它返回来的是一个数组
- this.$refs可以直接给组件命名,这样在拿数据的时候可以直接拿去,比上者更简便些
<template>
<div id="app">
<h3>app</h3>
{{msg_a}}/{{msg_b}}
<ChildA ref="a"></ChildA>
<ChildB ref="b"></ChildB>
</div>
</template>
<script>
import ChildA from './components/ChildA'
import ChildB from './components/ChildB'
export default {
name:'app',
data(){
return{
msgapp:'app数据',
msg_a:'-',
msg_b:'-',
}
},
components:{
ChildA,ChildB
},
methods:{},
mounted(){
//console.log('app',this.$children); //访问子,返回的是数组
//this.msg_b = this.$children[1].msgb;
//可以用$children也可以用$refs,$children稍微麻烦点,因为还有算组件所处位置;$refs是先把组件命名,再根据命名来获取对应的值
console.log("app",this.$refs);
this.msg_b = this.$refs.b.msgb;
this.$refs.b.show();
this.msg_a = this.$refs.a.msga;
}
}
</script>
ChildB.vue
<template>
<div class='child-b'>
<h3>child-b</h3>
</div>
</template>
<script>
export default{
data(){
return{
msgb:'child-b的数据'
}
},
mounted(){},
methods:{
show(){
console.log("b组件的函数")
}
}
}
</script>
<style>
.child-b{
background:green;
}
</style>
3.兄弟传兄弟
兄弟->兄弟
兄弟A->自定义事件->中间人(父)->props->兄弟B
4.爷传孙
A->...-> C
A作为祖先传递,C作为后代接受
<中间层组件 v-bind="$attrs" v-on="$listeners"></..>
$attrs 如果中间层组件没有接受props,给c的是所有props
$listeners 如果中间层组件没有触发,给c的是所有自定义事件
关系:
- App -> ChildA -> ChildC
App.vue
- 作为根,将要传的属性和事件写在中间的组件,利用中间的组件ChildA能承上启下而传给孙
<template>
<div id="app">
<h3>app</h3>
{{msg_c}}
<ChildA :msgApp="msgapp" @send_childc="updateChildC"></ChildA>
</div>
</template>
<script>
import ChildA from './components/ChildA'
export default {
name:'app',
data(){
return{
msgapp:'app数据',
msg_c:'-'
}
},
components:{
ChildA,
},
methods:{
updateChildC(data){
console.log('app收到了数据',data),
this.msg_c=data
}
},
mounted(){}
}
</script>
ChildA.vue
- 作为中间组件,来实现传递,传递给哪个组件记得要写上 v-bind="$ attrs" v-on="$listeners"
<template>
<div class='child-a'>
<h3>child-a</h3>
<ChildC v-bind="$attrs" v-on="$listeners"></ChildC>
</div>
</template>
<script>
import ChildC from './ChildC'
export default{
data(){
return{
msga:'child-a的数据',
}
},
components:{
ChildC
},
methods:{},
mounted(){}
}
</script>
<style>
.child-a{
background:blue;
}
</style>
ChildC.vue
- 为孙组件,需要用到props和$emit
<template>
<div class='child-c'>
<h3>child-c</h3>
{{msgApp}}
</div>
</template>
<script>
export default{
data(){
return{
msgc:'child-c的数据'
}
},
props:['msgApp'],
mounted(){
this.$emit('send_childc',this.msgc)
}
}
</script>
<style>
.child-c{
background:yellow;
}
</style>