Vue组件之间的传值

前言

组件系统是vue系统中非常重要的一个概念,我们可以利用vue提供的组件系统把一个复杂的项目,拆解成若干个小组件,组件不仅利于我们开发时对代码的编写,也利于对代码后期的维护。组件可以扩展 HTML 元素,封装可重用的代码。在较高层面上,组件是自定义元素,Vue.js 的编译器为它添加特殊功能。在有些情况下,组件也可以是原生 HTML 元素的形式,以 is 特性扩展。

组件的好处很多,但也带来了一个我们必须面对的问题,那就是组件之间的传值。

Component Tree

父组件向子组件传值

props是父组件向子组件传值的最常用方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<div id="root">
<childcp :val="parents"></childcp>
</div>
<script>

var childcp = {
props: ['val'],
template: `<div>子组件接受到了:{{val}}</div>`,
//子组件里的props通过接收父组件传过来的val值,直接就可以使用
}

var vm = new Vue({
el: '#root',
data: {
parents: '父组件的值'
},
components: {
childcp: childcp
}
})
</script>

Prop 是你可以在组件上注册的一些自定义特性。当一个值传递给一个 prop 特性的时候,它就变成了那个组件实例的一个属性。
一个组件默认可以拥有任意数量的 prop,任何值都可以传递给任何 prop
在上述模板中,你会发现我们能够在组件实例中访问这个值,就像访问 data 中的值一样。

子组件向父组件传值

$emit触发事件是子组件向父组件传值最常用的方法

我们可以调用内建的$emit并传入事件的名字,来向父级组件触发一个事件,然后我们可以用 v-on 在父组件上监听这个事件,就像监听一个原生 DOM 事件一样, $emit 的第二个参数可以传递一个值,然后当在父级组件监听这个事件的时候,我们可以通过 $event 访问到被抛出的这个值,或者,如果这个事件处理函数是一个方法,那么这个值将会作为第一个参数传入这个方法。

这里用一个计数的例子来说明:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
<div id="root">
<counter1 ref="one" :count="0" @count="countTotal"></counter1>
<counter2 ref="two" :count="0" @count="countTotal"></counter2>
<div class="total">总数: {{total}}</div>
</div>
<script>

var counter1 = {
props: ['count'],
data: function () {
return {
number: this.count
}
},
template: `<button @click="handleClick">点我+1: {{number}}</button > `,
methods: {
handleClick: function () {
this.number++;
this.$emit('count', 1);
}
}
}

var counter2 = {
props: ['count'],
data: function () {
return {
number: this.count
}
},
template: `<button @click="handleClick">点我+2: {{number}}</button > `,
methods: {
handleClick: function () {
this.number+= 2;
this.$emit('count', 2);
}
}
}

var vm = new Vue({
el: '#root',
data: {
total:0
},
components: {
counter1: counter1,
counter2: counter2
},
methods: {
countTotal(step) {
this.total = this.$refs.one.number+this.$refs.two.number
// 这两种方法都能求和
this.total+= step
// step接收$emit传递的第二个参数
}
}
})
</script>

效果

See the Pen WKWpqg by Sanakey (@Sanakey) on CodePen.

上述例子中的注意点

  • 一个组件的 data 选项必须是一个函数

    这样每个组件才会各自独立维护它的 count。 否则点击一个按钮就可能会影响到其它所有实例

  • 子组件内不要直接修改props值

    当props为引用类型时,修改子组件中props的数据会影响父组件的props数据。

    如果想要修改props值,一般做法是在子组件的data中定义一个新的变量保存props值,去修改新的变量而不是原props值。比如上述例子中就用number保存了count值。

  • ref使用在组件上时,$refs获取的是该组件的引用,ref使用在Dom元素中时,$refs获取的是该Dom元素

非父子组件、兄弟组件之间的传值

对于不是很复杂的非父子组件、兄弟组件之间的传值,vue官方提供了一种名为中央事件总线的方法。

新建一个Vue实例bus作为中央事件,把组件之间的传值,$emit触发事件与$on监听事件,全交给bus来完成。

  • 第一个组件中的methods方法里,用bus的$emit触发事件。
  • 另一个组件实例初始化时(mounted生命周期钩子中),用bus的$on监听$emit触发的事件。

具体实例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
<div id="root">
<child content="按钮一"></child>
<child content="按钮二"></child>
</div>
<script>
var bus = new Vue();
// bus作为中央事件总线

Vue.component('child', {
props: {
content: String
},
data: function () {
return {
selfContent: this.content
}
},
template: `<button @click="handleClick">{{selfContent}}</button>`,
methods: {
handleClick() {
bus.$emit('change', this.content);
// bus触发change事件
}
},
mounted: function () {
var This = this;

//bus监听change事件
bus.$on('change', function (msg) {
This.selfContent = msg;
//点击第一个组件按钮,第二个组件按钮的值变为‘按钮一’
//点击第二个组件按钮,第一个组件按钮的值变为‘按钮二’
})
}
})
var vm = new Vue({
el: '#root'
})
</script>

效果

See the Pen 总线,发布订阅模式 by Sanakey (@Sanakey) on CodePen.

结语

组件之间的传值主要就是上面几种类型,对于单页面应用这种复杂的组件间传值,Vue官方提供了vuex,vuex内容比较多,我将另外用一篇文章介绍,感谢阅读~~


感谢打赏,错误之处欢迎指正交流(`・ω・´) !~~



文章目录
  1. 1. 前言
  2. 2. 父组件向子组件传值
  3. 3. 子组件向父组件传值
  4. 4. 非父子组件、兄弟组件之间的传值
  5. 5. 结语
|