相关知识点
父组件传值到子组件
父组件传值到子组件基本方法有三个,分别为:
- 属性 props
- 引用 $refs
- 子元素 $children
日常开发中,我们用到 props 和 $refs 频率比较多,$children 相对较少些(我就没怎么使用过~)。
属性 props
在父组件中添加属性,在子组件中接收使用,例如:
父组件:
1
|
|
子组件:
1
2
3
4
5
|
< h1 >{{ msg }}</ h1 > props: { msg: String } |
引用 $refs
在父组件中可以使用 this.$refs.xxx 获取子组件中定义的数据或者方法,并使用。
父组件:
1
2
3
4
5
|
<HelloWorld ref= "hw" /> mounted() { this .$refs.hw.foo = "bar" ; } |
子组件:
1
2
3
4
5
6
7
|
<p>{{ foo }}</p> data() { return { foo: "foo" }; } |
注意事项:
this.$refs.xxx 不能在 created 生命周期中使用,因为真实的 DOM 还没有挂载完毕,如果非要想,可以使用 vm.$nextTick 来访问 DOM。或者也可以这样理解,父组件先于子组件创建,在父组件的 created 生命周期中子组件还没有创建,所以获取不到子组件。
在 Vue 中组件生命周期调用顺序如下:
组建的调用顺序都是 先父后子,渲染完成的顺序是 先子后父
组件的销毁操作是 先父后子,销毁完成的顺序是 先子后父
加载渲染过程
- 父 beforeCreate
- 父 created
- 父 beforeMount
- 子 beforeCreate
- 子 created
- 子 beforeMount
- 子 mounted
- 父 mounted
子组件更新过程
- 父 beforeUpdate
- 子 beforeUpdate
- 子 updated
- 父 updated
父组件更新过程
- 父 beforeUpdate
- 父 updated
销毁过程
- 父 beforeDestroy
- 子 beforeDestroy
- 子 destroyed
- 父 destroyed
1
2
3
4
5
6
7
8
9
10
11
12
13
|
created() { console.log( "第一个执行" ); console.log( this .$refs.hw); // undefined this .$nextTick(() => { console.log( "第三个执行" ); console.log( this .$refs.hw); // 此时可以获取到 }); } mounted() { console.log( "第二个执行" ); this .$refs.hw.foo = "bar" ; } |
子元素 $children
父组件:
1
|
this .$children[0].xx = "xxx" ; |
注意事项:
$children 获取当前实例的直接子组件。如果父组件中存在多个子组件,需要注意 $children 并不保证顺序,也不是响应式的。
子组件传值到父组件
子组件传值到父组件使用的方法是自定义事件。在子组件中派发,在父组件中监听。
注意事项: 事件的派发者是谁,事件的监听者就是谁,只不过声明的时候声明在父组件中了。
分为三种情况:不传递参数、传递一个参数、传递多个参数。
不传递参数
子组件:
1
|
this .$emit( 'childFoo' ); |
父组件:
1
2
3
4
5
6
7
|
<HelloWorld2 @childFoo= "onChildFoo" ></HelloWorld2> methods: { onChildFoo() { console.log( "====== onChildFoo ========" ); } } |
传递一个参数
在父组件中使用 $event 接收参数。
子组件:
1
|
this .$emit( 'childFooSingle' , 'foo' ); |
父组件:
1
2
3
4
5
6
7
|
<HelloWorld2 @childFooSingle= "onChildFooSingle($event)" ></HelloWorld2> methods: { onChildFooSingle(e) { console.log(e); // foo } } |
传递多个参数
在父组件中使用 arguments 接收参数,会以数组的形式传递。
子组件:
1
|
this .$emit( 'childFooMultiple' , 'foo' , 'bar' , 'dong' ); |
父组件:
1
2
3
4
5
6
7
8
9
|
<HelloWorld2 @childFooSingle= "onChildFooMultiple(arguments)" ></HelloWorld2> methods: { onChildFooMultiple(msg) { console.log(msg[0]); // foo console.log(msg[1]); // bar console.log(msg[2]); // dong } } |
兄弟组件之间传值
兄弟组件之间传值可以通过共同的父辈组件搭桥进行传递,例如:$parent、$root。
兄弟组件1:
1
|
this .$parent.$on( 'foo' , handle); |
兄弟组件2:
1
|
this .$parent.$emit( 'foo' ); |
祖代和后代之间传值
由于组件嵌套层数过多,使用 props 进行传递不切实际,vue 提供了 provide/inject API 完成该任务。
provide/inject 能够实现祖先给后代传值。
祖代:
1
2
3
|
provide() { return {foo: 'foo' } } |
后代:
1
|
inject: [ 'foo' ] |
注意:provide 和 inject 主要为高阶组件/组件库提供用例,并不推荐直接用于应用程序代码中,我们更多会在开源组件库中见到。但是,反过来想要后代给祖代传值,这种方案就不行了!!!
官方提示:provide 和 inject 绑定并不是响应式的。这是刻意为之的。然而,如果你传入了一个可监听的对象,那么其对象的 property 还是可响应式的。
祖代:
1
2
3
4
5
6
7
8
9
10
|
provide() { return { dong: this .home }; }, data() { return { home: [ "App home" ] }; } |
后代:
1
2
3
4
|
inject: [ "dong" ] this .dong = [ "App data" ]; // 会报错,Avoid mutating an injected value directly since the changes will be overwritten whenever the provided component re-renders this .dong.push( "App data" ); // 可以修改成功 |
任意两个组件之间传值
任意两个组件之间传值有两种方案:事件总线、Vuex。
事件总线
创建一个 Bus 类负责事件派发、监听和回调管理。
首先创建一个 bus.js,并在 main.js 中引入,然后在组件中使用:
第一步:新建 plugins/bus.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
class Bus{ constructor(){ this .callbacks = {} } $on(name, fn){ this .callbacks[name] = this .callbacks[name] || [] this .callbacks[name].push(fn) } $emit(name, args){ if ( this .callbacks[name]){ this .callbacks[name].forEach(cb => cb(args)) } } } export default Bus; |
第二步:main.js 中引入
1
2
|
import Bus from "./plugins/bus" ; Vue.prototype.$bus = new Bus() |
第三步:在组件中使用
组件1:
1
|
this .$bus.$on( 'foo' , handle) |
组件2:
1
|
this .$bus.$emit( 'foo' ) |
Vuex
创建唯一的全局数据管理者 store,通过它管理数据并通知组件状态变更。可以自行先了解一下官方文档Vuex,具体详细使用后续会写一个专题~
总结
到此这篇关于Vue组件化常用方法之组件传值与通信的文章就介绍到这了,更多相关Vue组件传值与通信内容请搜索服务器之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持服务器之家!
原文链接:https://juejin.cn/post/6936986540753027108