组件之间的通讯
# 组件之间的通讯
Vue组件之间的通讯有多种方法:①父组件给子组件传值。②子组件给父组件传值。③兄弟组件之间的传值。组件之间的通讯在实际开发中可增加代码的重用性和扩展性。
# 父组件给子组件传值
组件是当作自定义元素来使用的,HTML元素有属性,同样,组件也可以有属性,利用属性给子组件内部传值,子组件使用props来接收。代码如下:
//子组件
    let ChildrenComponent={
        //使用props接收属性
        props:["post-title","sub-title"],
        template:`
            <div>{{postTitle}}-{{subTitle}}</div>
        `
    };
//父组件
    let ParentComponent={
        data(){
            return {
                title:"我是父组件的title",
                subTitle:"我是父组件的subTitle"
            }
        },
          template: `
            <div>
                <ChildrenComponent :post-title="title" :sub-title="subTitle"></ChildrenComponent>
            </div>
          `,
        components:{
            ChildrenComponent
        }
    };
new Vue({
        el:"#app",
        components:{
            ParentComponent
        },
        template:`
            <div>
                <ParentComponent></ParentComponent>
            </div>
        `
    })
注意:接收的属性名是kebab-case(短横线分隔命名)来使用,在Mustache标签里面变量名要用camelCase(驼峰命名)来使用,因为Mustache标签不支持kebab-case。
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
Vue还支持属性类型的验证,比如子组件接收的属性值应该是一个对象类型,结果父组件传的是一个字符串类型的值,这显然不符合要求,这时需要属性验证。代码示例如下:
//使用props接收属性并验证类型
        props:{
            "post-title":{
                type:String
            },
            "sub-title":{
                type:String
            }
        },
2
3
4
5
6
7
8
9
10
验证的type值可以是下列原生构造函数中的一个:
- lString
- lNumber
- lBoolean
- lArray
- lObject
- lDate
- lFunction
- lSymbol
在实际开发中推荐使用验证属性的方式接收prop。
验证属性的方式还支持,父组件传过来的属性是否为必有属性,代码如下:
 props:{
      "post-title":{
        type:String,
        required:true //父组件必须传入此属性
      }
    },
2
3
4
5
6
验证属性的方式还支持默认值,在组件没有传入属性的时候,可以给一个默认值,代码如下:
//使用props接收属性并验证类型
        props:{
            "post-title":{
                type:String,
                default:"我是post-title默认值"
            }
        },
2
3
4
5
6
7
8
如果是Array或Object类型默认值需要用工厂函数返回,代码如下:
props:{
            "list":{
                type:Array,
                default:()=>[] //工厂函数返回默认值
            }
        },
2
3
4
5
6
7
组件也可以接收任意的属性,比如给组件添加class或style属性等,而这些外部设置的属性会被添加到这个组件的跟元素上面。代码如下:
 //子组件
    let InputComponent={
        template:`
                <input type="text" class=" input"  />
        `
    };
   //父组件
    let ParentComponent={
          template: `
            <div>
                <InputComponent class="my-input"></InputComponent>
            </div>
          `,
        components:{
            InputComponent
        }
    };
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
而对于其他属性而言,则会覆盖,代码如下:
//父组件
 <InputComponent class="my-input" type="checkbox" checked></InputComponent>
在<InputComponent>组件上面添加属性type和checked,InputComponent组件内部根元素input存在属性type则覆盖,最终type的值为checkbox,checked属性不存在,则添加checked属性。
2
3
4
5
如果不希望根组件继承外部设置的属性,可以在子组件的选项中设置属性inheritAttrs的值为false,代码如下:
 //子组件
    let InputComponent={
        template:`
                <input type="text" class="input" />
        `,
        inheritAttrs:false//根元素不继承外部设置的属性
    };
2
3
4
5
6
7
8
由于prop传递数据属于单向数据流,父组件的属性变化会向下传递给子组件,但是反过来却不行,这可以防止子组件意外改变父组件的状态,从而导致应用程序的数据流难以理解。每次父组件更新数据时,子组件的prop都会刷新为最新的值。这意味着我们不应该在组件内部直接更改prop,如果更改Vue会在浏览器的控制台中给出警告。
可以使用本地的data方法或是引用类型来解决。
# 子组件给父组件传值
在Vue中是通过自定义事件来实现的,子组件使用$emit()方法触发事件,父组件使用v-on指令监听子组件的自定义事件来完成通讯。
$emit()方法的语法形式如下:
vue.$emit(eventName,[...args])
eventName是自定义事件名称,args是附加参数
# 兄弟组件之间传值
在实际开发中也会出现兄弟组件(非父子组件)之间传值的需求,实现的方式很简单,声明一个bus变量其值为new Vue(),然后在A组件bus.$emit()方法传值,B组件用bus.$on方法接收A组件传过来的值,来完成兄弟组件之间的传值。
# 父组件与子组件实现双向绑定
在开发UI库时都是对HTML表单控件进行封装的,比如自定义了一个input组件,在自定义的input组件上面添加v-model指令,默认v-model指令是不生效的,这时我们要手动让它支持v-model指令,常用的解决方案有两种:
第一种使用computed解决,第二种使用model解决。
# 父组件调用子组件的方法
在实际开发中经常会遇到父组件调用子组件的方法,其实很简单,通过ref就可以直接调用子组件里面的方法
