组件是 vue.js 最强大的功能之一, 而组件实例的作用域是相互独立的, 这就意味着不同组件之间的数据无法相互引用. 那么组件间如何通信, 也就成为了 vue 中重点知识了. 这篇文章将会通过 props,$ref 和 $emit 这几个知识点, 来讲解如何实现父子组件间通信.
在说如何实现通信之前, 我们先来建两个组件 father.vue 和 child.vue 作为示例的基础.
- // 父组件
- <template>
- <div>
- <h1 > 我是父组件!</h1>
- <child></child>
- </div>
- </template>
- <script>
- import Child from '../components/child.vue'
- export default {
- components: {Child},
- }
- </script>
- // 子组件
- <template>
- <h3 > 我是子组件!</h3>
- </template>
- <script>
- </script>
这两部分的代码都很清晰明了, 父组件通过 import 的方式导入子组件, 并在 components 属性中注册, 然后子组件就可以以标签 < child > 的形式嵌套进父组件了. 运行 father.vue 后的效果是这样的:
示例效果一
1. 通过 prop 实现通信
子组件的 props 选项能够接收来自父组件数据. 没错, 仅仅只能接收, props 是单向绑定的, 即只能父组件向子组件传递, 不能反向. 而传递的方式也分为两种:
(1) 静态传递
子组件通过 props 选项来声明一个自定义的属性, 然后父组件就可以在嵌套标签的时候, 通过这个属性往子组件传递数据了.
- <!-- 父组件 -->
- <template>
- <div>
- <h1 > 我是父组件!</h1>
- <child message="我是子组件一!"></child> // 通过自定义属性传递数据
- </div>
- </template>
- <script>
- import Child from '../components/child.vue'
- export default {
- components: {Child},
- }
- </script>
- <!-- 子组件 -->
- <template>
- <h3>{{message}}</h3>
- </template>
- <script>
- export default {
- props: ['message'] // 声明一个自定义的属性
- }
- </script>
(2) 动态传递
我们已经知道了可以像上面那样给 props 传入一个静态的值, 但是我们更多的情况需要动态的数据. 这时候就可以用 v-bind 来实现. 通过 v-bind 绑定 props 的自定义的属性, 传递去过的就不是静态的字符串了, 它可以是一个表达式, 布尔值, 对象等等任何类型的值.
- <!-- 父组件 -->
- <template>
- <div>
- <h1 > 我是父组件!</h1>
- <child message="我是子组件一!"></child>
- <!-- 这是一个 JavaScript 表达式而不是一个字符串.-->
- <child v-bind:message="a+b"></child>
- <!-- 用一个变量进行动态赋值.-->
- <child v-bind:message="msg"></child>
- </div>
- </template>
- <script>
- import Child from '../components/child.vue'
- export default {
- components: {Child},
- data() {
- return {
- a:'我是子组件二!',
- b:112233,
- msg: '我是子组件三!'+ Math.random()
- }
- }
- }
- </script>
- <!-- 子组件 -->
- <template>
- <h3>{{message}}</h3>
- </template>
- <script>
- export default {
- props: ['message']
- }
- </script>
出来的效果是这样的:
示例效果二
2. 通过 $ref 实现通信
对于 ref 官方的解释是: ref 是被用来给元素或子组件注册引用信息的. 引用信息将会注册在父组件的 $refs 对象上.
看不懂对吧? 很正常, 我也看不懂. 那应该怎么理解? 看看我的解释:
如果 ref 用在子组件上, 指向的是组件实例, 可以理解为对子组件的索引, 通过 $ref 可能获取到在子组件里定义的属性和方法.
如果 ref 在普通的 DOM 元素上使用, 引用指向的就是 DOM 元素, 通过 $ref 可能获取到该 DOM 的属性集合, 轻松访问到 DOM 元素, 作用与 JQ 选择器类似.
那如何通过 $ref 实现通信? 下面我将上面 prop 实现的功能, 用 $ref 实现一遍:
- <!-- 父组件 -->
- <template>
- <div>
- <h1 > 我是父组件!</h1>
- <child ref="msg"></child>
- </div>
- </template>
- <script>
- import Child from '../components/child.vue'
- export default {
- components: {Child},
- mounted: function () {
- console.log( this.$refs.msg);
- this.$refs.msg.getMessage('我是子组件一!')
- }
- }
- </script>
- <!-- 子组件 -->
- <template>
- <h3>{{message}}</h3>
- </template>
- <script>
- export default {
- data(){
- return{
- message:''
- }
- },
- methods:{
- getMessage(m){
- this.message=m;
- }
- }
- }
- </script>
从上面的代码我们可以看见, 通过 ref='msg'可以将子组件 child 的实例指给了 ref, 并且通过 $refs.msg.getMessage(), 就能使用子组件的 getMessage 方法并将参数传递给子组件, 从而实现数据传递. 下面是 "console.log( this.$refs.msg);" 打印出来的东西, 这可以让大家更加了解, 究竟通过 ref 我们获取了什么:
console.log
最后的效果是这样的:
示例效果三
这里再补充一点就是, prop 和 $ref 之间的区别:
prop 着重于数据的传递, 它并不能调用子组件里的属性和方法. 像创建文章组件时, 自定义标题和内容这样的使用场景, 最适合使用 prop.
$ref 着重于索引, 主要用来调用子组件里的属性和方法, 其实并不擅长数据传递. 而且 ref 用在 dom 元素的时候, 能使到选择器的作用, 这个功能比作为索引更常有用到.
3. 通过 $emit 实现通信
上面两种示例主要都是父组件向子组件通信, 而通过 $emit 实现子组件向父组件通信.
对于 $emit 官网上也是解释得很朦胧, 我按我自己的理解就是, 子组件中的 $emit 就是发送参数, 父组件中的 "@关键名" 就是接收参数, 然后基于这个逻辑丰富代码, 实现你想要的功能.
- <template>
- <div>
- <h1>{{title}}</h1>
- <child @getMessage="showMsg"></child>
- </div>
- </template>
- <script>
- import Child from '../components/child.vue'
- export default {
- components: {Child},
- data(){
- return{
- title:''
- }
- },
- methods:{
- showMsg(title){
- this.title=title;
- }
- }
- }
- </script>
- <template>
- <h3 > 我是子组件!</h3>
- </template>
- <script>
- export default {
- mounted: function () {
- this.$emit('getMessage', '我是父组件!')
- }
- }
- </script>
示例效果三
来源: http://www.jianshu.com/p/91416e11f012