Vue组件和组件之间的通信

组件之间的data作用域是独立的,不能相互访问的。所以我们需要通过一些特别的手法让它们之间实现数据通信。

常见的组件通讯方式分为三种:

  • 父传子
  • 子传父
  • 同级互传

1. 父传子

分成两步:

  1. 在父组件中给子组件标签绑定属性,属性值为要传递的值。
  2. 在子组件中,通过props选项接收传递的属性,然后就可以直接使用了。

为了方便演示,这里采用HTML的组件写法:

<div id="app">
    <!-- 直接在组件标签名上添加传递的属性与属性值 -->
    <test :propmsg="msg" :product="good"></test>
</div>
<script>
    var vm = new Vue({
        data(){
            return {
                good: '《钢铁是怎样炼成的》',
                msg: '孩儿啊,最近过的如何啊?'
            }
        },
        components:{
            // 注册子组件
            test:{
                // 通过 props 接收父组件传递的属性
                props: ['propmsg', 'product']
                template:"<div>我是子组件,接受来自父组件的值---{{ propmsg }} -- {{ product }}</div>"
            }
        }
    }).$mount('#app')
</script>

注意:千万不要在子组件中去修改从父组件传递过来的属性。否则会报错:

因为Vue采用的是单向数据流,所有的 prop 都使得其父子 prop 之间形成了一个单向下行绑定:父级 prop 的更新会向下流动到子组件中,但是反过来则不行。这样会防止从子组件意外变更父级组件的状态,从而导致你的应用的数据流向难以理解。另外,每次父级组件发生变更时,子组件中所有的 prop 都将会刷新为最新的值。这意味着你不应该在一个子组件内部改变 prop。如果你这样做了,Vue 会在浏览器的控制台中发出警告。

prop 的命名规范
HTML 中的属性名是大小写不敏感的,所以浏览器会把所有大写字符解释为小写字符。这意味着当你使用 DOM 中的模板时,camelCase (驼峰命名法) 的prop名需要使用其等价的 kebab-case (短横线分隔命名) 命名,如下所示:

// 属性名是驼峰
props: ['postTitle']
<!-- 在 HTML 中使用 短横线 -->
<blog-post post-title="hello!"></blog-post>

有些时候我们可能想对父组件传递的属性做出一些限制,如类型、内容、是否具有默认值、是否必填等,这时候我们可以将props写为对象形式:

new Vue({
    // 改为对象形式,添加多种设置
    props: {
        propmsg: {
            // 控制类型,多个类型可以写为数组形式 [String, Number, ...]
            type: String,
            // 默认值
            default: '默认值',
            // 是否必填,默认false
            required: false,
            // 自己定义的校验函数,参数为父组件传递的属性值,返回false则会在控制台报错
            validator(value){
                console.log('父组件传递的值为:', value)
                return true/false
            }
        },
        // 也可以直接写为  属性名: 类型
        product: String
    }
}).$mount('#app')

2. 子传父

子组件到父组件的通信,要借助Vue实例的$emit方法,也是需要分成两步:

  1. 在子组件中,需要$emit一个事件

  2. 父组件中,在子组件的标签上绑定它$emit的事件

<div id="app">
    <!-- 绑定子组件 $emit 的事件名 @子传的事件名='自己的监听函数' -->
    <com @give="receive"></com>
</div>
<script>
    var vm = new Vue({
        el : "#app",
        components: {
            com: {
                template: '<button @click="trans">给父组件传值</button>',
                methods:{
                    trans(){
                        // this.$emit('事件名', 传递的值1, arg2, ...)
                        this.$emit('give', "闹,给你1000块打麻将")
                    }
                }
            }
        },
        methods: {
            // 监听函数的参数为子组件传递的值
            receive(msg){
                console.log('接收到子组件传递的信息:', msg)
            }
        }
    })
</script>

2.1 sync 修饰符

如果确实需要在子组件中修改父组件传递过来的值,可以借助sync修饰符。

写法是在子组件标签上传递属性后面加上sync修饰符,在子组件更改该属性值的时候传一个this.$emit('update:修改的属性名', 修改的值);,就可以实现修改的效果。

<div id="app">
    <!-- 绑定的属性添加 sync 修饰符 -->
    <com :message.sync= "message"></com>
</div>
<script>
    var vm = new Vue({
        el : "#app",
        data(){
            return {
                message: "父元素里面的值"
            }
        },
        components: {
            com: {
                props: ["message"],
                template: "<h3 @click='changeProp'>子组件 {{message}}</h3>",
                methods:{
                    changeProp(){
                        // 使用 update:属性名 作为发射的事件名,修改父组件传递的属性值
                        this.$emit('update:message', "改变之后的")
                    }
                }
            }
        }
    })
</script>

3. 同级传递

同级的组件通过添加$bus(中央事件总线)传递。

  1. 我们需要添加$bus方法,vue 的实例上没有这个方法

  2. 同级组件直接可以通过$emit$on实现值的传递

<div id="app">
    <zujian1></zujian1>
    <zujian2></zujian2>
</div>
<script>
    // 给原型添加属性,所有的Vue实例都会拥有该属性
    // 这里赋值为一个Vue实例,主要是要借用Vue实例上的 $emit 和 $on 方法
    Vue.prototype.$bus = new Vue();

    var vm = new Vue({
        components: {
            "zujian1": {
                data(){
                    return {
                        msg: ''
                    }
                }
                created () {
                    // 实例可以使用原型的属性 $bus
                    // $on 是vue提供的方法,用于接收 $emit 的值,方式为:$on('$emit的事件名', 回调函数)
                    this.$bus.$on("busevent", val =>{
                        // 参数就是$emit传递的值
                        this.msg = val;
                    });
                },
                template :"<p>zujian2 传递过来的值是 {{msg}}</p>"
            },
            "zujian2": {
                methods:{
                    send(){
                        // 类似于子传父
                        this.$bus.$emit("busevent", '好朋友,你在干什么?');
                    }
                },
                template :"<button @click='send'>给zujian1传递数据</button>"
            },
        }
    }).$mount('#app')
</script>

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值