相关知识点
- 父组件传值到子组件
- 子组件传值到父组件
- 兄弟组件之间传值
- 祖代和后代之间传值
- 任意两个组件之间传值
父组件传值到子组件
父组件传值到子组件基本方法有三个,分别为:
- 属性 props
- 引用 $refs
- 子元素 $children
日常开发中,我们用到 props 和 $refs 频率比较多,$children 相对较少些(我就没怎么使用过~)。
属性 props
在父组件中添加属性,在子组件中接收使用,例如:
父组件:
<HelloWorld msg="Welcome to Your Vue.js App" />
子组件:
<h1>{{ msg }}</h1> props: { msg: String }
引用 $refs
在父组件中可以使用 this.$refs.xxx 获取子组件中定义的数据或者方法,并使用。
父组件:
<HelloWorld ref="hw" /> mounted() { this.$refs.hw.foo = "bar"; }
子组件:
<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
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
父组件:
this.$children[0].xx = "xxx";
注意事项:
$children 获取当前实例的直接子组件。如果父组件中存在多个子组件,需要注意 $children 并不保证顺序,也不是响应式的。
子组件传值到父组件
子组件传值到父组件使用的方法是自定义事件。在子组件中派发,在父组件中监听。
注意事项: 事件的派发者是谁,事件的监听者就是谁,只不过声明的时候声明在父组件中了。
分为三种情况:不传递参数、传递一个参数、传递多个参数。
不传递参数
子组件:
this.$emit('childFoo');
父组件:
<HelloWorld2 @childFoo="onChildFoo"></HelloWorld2> methods: { onChildFoo() { console.log("====== onChildFoo ========"); } }
传递一个参数
在父组件中使用 $event 接收参数。
子组件:
this.$emit('childFooSingle', 'foo');
父组件:
<HelloWorld2 @childFooSingle="onChildFooSingle($event)"></HelloWorld2> methods: { onChildFooSingle(e) { console.log(e); // foo } }
传递多个参数
在父组件中使用 arguments 接收参数,会以数组的形式传递。
子组件:
this.$emit('childFooMultiple', 'foo', 'bar', 'dong');
父组件:
<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:
this.$parent.$on('foo', handle);
兄弟组件2:
this.$parent.$emit('foo');
祖代和后代之间传值
由于组件嵌套层数过多,使用 props 进行传递不切实际,vue 提供了 provide/inject API 完成该任务。
provide/inject 能够实现祖先给后代传值。
祖代:
provide() { return {foo: 'foo'} }
后代:
inject: ['foo']
注意:provide 和 inject 主要为高阶组件/组件库提供用例,并不推荐直接用于应用程序代码中,我们更多会在开源组件库中见到。但是,反过来想要后代给祖代传值,这种方案就不行了!!!
官方提示:provide 和 inject 绑定并不是响应式的。这是刻意为之的。然而,如果你传入了一个可监听的对象,那么其对象的 property 还是可响应式的。
祖代:
provide() { return { dong: this.home }; }, data() { return { home: ["App home"] }; }
后代:
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
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 中引入
import Bus from "./plugins/bus"; Vue.prototype.$bus = new Bus()
第三步:在组件中使用
组件1:
this.$bus.$on('foo', handle)
组件2:
this.$bus.$emit('foo')
Vuex
创建唯一的全局数据管理者 store,通过它管理数据并通知组件状态变更。可以自行先了解一下官方文档Vuex,具体详细使用后续会写一个专题~
总结
到此这篇关于Vue组件化常用方法之组件传值与通信的文章就介绍到这了,更多相关Vue组件传值与通信内容请搜索NICE源码以前的文章或继续浏览下面的相关文章希望大家以后多多支持NICE源码!