当前位置:主页 > 网页前端 > vue >

Vue组件化常用方法之组件传值与通信

时间:2021-10-06 09:08:25 | 栏目:vue | 点击:

相关知识点

父组件传值到子组件

父组件传值到子组件基本方法有三个,分别为:

日常开发中,我们用到 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 中组件生命周期调用顺序如下:

组建的调用顺序都是 先父后子,渲染完成的顺序是 先子后父

组件的销毁操作是 先父后子,销毁完成的顺序是 先子后父

加载渲染过程

子组件更新过程

父组件更新过程

销毁过程

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,具体详细使用后续会写一个专题~

总结

您可能感兴趣的文章:

相关文章