Vue学习笔记:组件之间的通信方式

在Vue中组件是实现模块化开发的主要内容,而组件的通信更是vue数据驱动的重点,总结一下目前我了解的组件之间数据通信和访问的方法。

v-bind和props

父组件在子组件上使用v-bind绑定数据

1
2
3
<div>
<child :child-msg="msg"></child> //这里必须要用 - 代替驼峰
</div>

1
2
3
4
5
data () {
return {
msg: 'hello'
};
}

子组件通过props来接收数据

1
<div>{{childMsg}}</div>  //hello

1
props: ['childMsg']

可以通过使用this.childMsg调用数据。

自定义事件和$emit

子组件要向父组件传递数据,需要使用触发事件的方式,使用$emit通知父组件改变数据

1
<button @click='up'>发送</button>

1
2
3
4
5
6
7
8
9
10
data () {
return {
msg: 'hello'
};
}
methods: {
up () {
this.$emit('getChildMsg', this.msg);
}
}

父组件监听子组件触发的up事件,然后调用change方法

1
2
3
<div>
<child @getChildMsg="change"></child>
</div>

1
2
3
4
5
methods: {
change(msg) {
console.log(msg); // hello
}
}

v-model

在介绍了props$emit之后,就可以根据它们来实现在自定义组件上使用v-model来进行数据通信了。
首先简单的解释一下v-model与二者的关系,以下两中写法实现的效果相同:

1
2
3
4
5
6
7
8
9
10
// 使用v-model
<component v-model='msg'></component>

// 使用props和$emit
<component :value='msg' @input='getMsg'></component>

……
getMsg(value){
this.msg = value;
}

对于v-model绑定的变量,相当于在子组件上面绑定了一个value属性,还可以通过接收子组件传递的input属性来再次赋值。
这么解释太抽象了,下面是一个简单的封装input组件的例子:
父组件

1
<my-input v-model='number'></my-input>

子组件

1
2
3
<div>
<input type="text" v-model='inputValue'>
</div>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<script>
export default {
data () {
return {
inputValue: ''
}
},
props: {
value: [String, Number] // 拿到父组件传递的值
},
mounted () {
this.inputValue = this.value;
},
watch: {
value: function (val) { // 监听父组件传值变化,更新绑定值
this.inputValue = val;
},
inputValue: function (val) { // 内容变化时,通知父组件
this.$emit('input', val);
}
}
}
</script>

路由传参

在路由页面跳转时,可以通过传递参数的方式拿到数据。

  • router-link
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<router-link 
:to="{
path: '/path',
query: {
name: name
}
}">
</router-link>
<router-link
:to="{
name: '/path',
params: {
name: name
}
}">
</router-link>

需要注意的是,path和query,name和params都是成对出现的,即使用path进行路由跳转时,params的值是拿不到的,只能设置query,反之亦然。
params和query都可以传递,区别在于后者会出现在url上,考虑到刷新页面的情况,建议使用query

  • $router方式
1
2
3
4
5
6
7
8
9
10
11
12
this.$router.push({
path: '/path',
query: {
name: name
}
})
this.$router.push({
name: 'name', //路由的name值
params: {
name: name
}
})

参数的规则和router-link相同

  • 获取参数的方式

对于使用params方式传递的参数

1
this.$route.params.name

对于使用query方式传递的参数

1
this.$route.query.name

  • 动态路由匹配

在定义router时使用动态路径参数,以冒号开头

1
2
3
4
5
const router = new VueRouter({
routes: [
{ path: '/user/:id', component: User }
]
})

这时/user/foo/user/bar 都将映射到相同的路由,在路由页面中获取:

1
this.$route.params.user

  • props 路由传参
1
2
3
4
5
const router = new VueRouter({
routes: [
{ path: '/user/:id', component: User, props: true },
]
})

将路由的props属性设置为true,在路由页就可以通过使用props拿到数据:

1
props: ['id']

通过slot通信

关于slot的使用就不介绍了,下面简单举个栗子

1
2
3
4
5
6
7
8
9
// 子组件
<div>
<slot msg="hi"></slot>
</div>

// 父组件
<child>
<div slot-scope="scope">{{ scope.msg }}</div> // hi
</child>

在slot插槽上绑定的数据可以通过slot-scope拿到,这里也支持解构的写法

1
2
3
<child> 
<div slot-scope="{ msg }">{{ msg }}</div> // hi
</child>

设置中间件

创建一个事件中心,相当于中间件,可以用它来传递事件和接收事件

1
var vm = new Vue();

发送数据的组件触发

1
<button @click="send">发送</button>

1
2
3
4
5
methods: {
send() {
vm.$emit('change','hello');
}
}

接收数据的组件

1
2
3
4
5
created() {
vm.$on('change', (msg) => {
this.msg = msg; //hello
});
}

在vue文件中需要使用中间件通信时,创建中间件,如下

1
2
3
import Vue from 'Vue';

export default new Vue();

使用时在组件中import导入即可

父组件访问子组件

当我们需要在父组件中访问子组件时,可以使用$children或者$ref

1
2
3
4
5
6
7
8
9
10
11
12
//子组件1
data () {
return {
msg: '这是子组件1的信息'
}
}
//子组件2
data () {
return {
msg: '这是子组件2的信息'
}
}

  • $children返回所有子组件的实例,是一个数组
1
2
3
<div>
<button @click="showmsg">显示子组件信息</button>
</div>
1
2
3
4
5
6
7
methods: {
showmsg () {
for(var i = 0; i < this.$children.length; i++) {
console.log(this.$children[i].msg)
}
}
}
  • 使用ref为子组件指定一个索引ID,可以在父组件使用$refs访问到
1
2
3
4
5
<div id="count">
<button @click="showmsg">显示子组件信息</button>
<child1 ref='c1'></child1>
<child2 ref='c2'></child2>
</div>
1
2
3
4
5
6
methods: {
showmsg () {
console.log(this.$refs.c1.msg)
console.log(this.$refs.c2.msg)
}
}

在调用子组件方法时,可以通过传参的方式把数据传到子组件

1
2
3
4
5
6
//父组件
this.$refs.child.show('hi')
//子组件
show(msg){
this.msg = msg //hi
}

Promise方式

子组件中定义父组件需要调用的方法,并返回一个promise对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
data () {
return {
msg : 'hello',
promise : {
resolve: null,
reject : null
}
}
}
methods: {
show() {
return new Promise((resolve, reject) => {
this.promise.resolve = resolve;
this.promise.reject = reject;
});
},
send () {
this.promise.resolve(this.msg);
}
}

调用send方法时,执行promise的resolve方法,向父组件返回msg,父组件调用show方法拿到返回值

1
<child ref="child"></child>

1
2
3
4
//调用的方法中
this.$refs.child.show().then(result => {
console.log(result) //hello
});

result就是子组件返回的数据,即msg

Vuex

将数据存放在store中,另一组件获取state中的数据,或者watch state中数据的变化,来进行相应的操作
‘Vuex简单入门’

子组件访问父组件

在子组件中使用$parent可以获取到父组件的对象,使用方法同$children

访问根组件

使用$root可以获取当前组件树的根Vue实例。如果当前实例没有父实例,此实例将会是其自已

文章目录
  1. 1. v-bind和props
  2. 2. 自定义事件和$emit
  3. 3. v-model
  4. 4. 路由传参
  5. 5. 通过slot通信
  6. 6. 设置中间件
  7. 7. 父组件访问子组件
  8. 8. Promise方式
  9. 9. Vuex
  10. 10. 子组件访问父组件
  11. 11. 访问根组件
|