vue父子组件通信/访问

74 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第2天

父子组件通信

通信方式:

  • 通过props向子组件传递数据
  • 通过事件向父组件发送消息

在子组件中存入props字符串数组,里面的字符串名任意取,之后这些字符和父组件中data中的数据做绑定:在组件标签中,绑定与字符数组中字符相同的属性,令其等于父组件中data域要绑定的数据名。

    <script>
        window.onload = function(){
            const cpn = {
                template: `
                    <div>
                        {{cmessage}}    
                    </div>
                `,
                props: ["cmessage"]
                
            }
            const app = new Vue({
                el:'#app',
                data:{
                    message: 111,
                },
                methods:{
                    itemClick(){
                        
                    }
                },
                components: {
                    cpn
                }
            })
        }
    </script>
</head>
<body>
    <div id="app">
        <cpn :cmessage="message"></cpn>
    </div>

绑定后,在template中也可通过props中定义的属性名使用

如果不用v-bind,则会将内容当作字符串传递给属性

当需要对props进行类型验证时,就需要对象写法了:

props: {
    //用法一:类型限制
    cmovies: Array,
    //用法二:提供一些默认值
    cmessage: {
        type: String,
        default: 'aaaaa',
        required: true //必须在标签中绑定
    },
    //类型是对象或者数组时,默认值必须是一个函数
    cbooks: {
        type: Array,
        default(){
            return []
        }
    }
}

type其他的可选值:

  • null匹配任何类型
  • [String, Number]多个可能的类型

自定义验证函数:

props:{
    prop:{
        validator:function(value){
            //这个值必须匹配下列字符串中的一个
            return ['success', 'warning', 'danger'].indexOf(value) !== -1
        }
    }
}

自定义类型:

function Person(firstName, lastName){
    this.firstName = firstName
    this.lastName = lastName
}
​
vue.component('blog-post',{
    props: {
        author: Person
    }
})

注意在起名时,若使用驼峰命名法,v-bind绑定时,要转换为 - 连接

在子组件中,必须有一个根元素div包裹其内元素

<!--通过$emit()向父组件发送信息-->
<div id="app">
    <!-- 绑定监听子组件发射出去的事件,绑定时省略掉括号,若emit中有传入数据,则默认传入emit的第二个参数 -->
    <cpn @itemclick="cpnclick"></cpn>
</div>
<template id="cpn">
    <div>
        <button @click="btnclick">
            {{message}}
        </button>
    </div>
</template>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
    const cpn = {
        template: `#cpn`,
        data(){
            return {
                message:'点我向父组件发送消息'
            }
        },
        methods:{
            btnclick(){
                //发射
                this.$emit('itemclick');//第二个参数可选,为要传入的数据
            }
        }
    }
    const app = new Vue({
        el:'#app',
        data: {
            message: 0
        },
        components:{
            cpn
        },
        methods:{
            cpnclick(){
                console.log("子组件的消息传到了这里")
            }
        }
    })
</script>

在子组件中实现与父组件数据双向绑定

不能直接与props中的参数绑定,虽然可以运行,但会显得数据很乱,并且报错

<div id="app">
        <cpn :mynumber1="number1" :mynumber2="number2" @changenum1="change1"></cpn>
        {{number1}}
    </div>
    <template id="cpn">
        <div>
            <!--与组件的data域数据进行双向绑定-->
            <input v-model="cpnnumber1" @input="changenum1"> <br>
            props:{{mynumber1}} <br>
            cpn:{{cpnnumber1}} <br>
            <input v-model="cpnnumber2" > <br>
            props:{{mynumber2}} <br>
            cpn:{{cpnnumber2}} <br>
        </div>
    </template>
    <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
    <script>
        const cpn = {
            template: `#cpn`,
            data(){
                return {
                    //在这里将props得到的数据绑定进自己的data域中
                    cpnnumber1: this.mynumber1,
                    cpnnumber2: this.mynumber2
                }
            },
            props: {
                mynumber1: Number,
                mynumber2: Number
            },
            methods: {
                changenum1(mynumber1){
                    return this.$emit('changenum1',this.cpnnumber1);
                }
            }
        }
        const app = new Vue({
            el: `#app`,
            data: {
                number1:0,
                number2:1,
            },
            components: {
                cpn
            },
            methods: {
                change1(num1){
                    this.number1 = parseInt(num1);
                }
            }
        })
    </script>

讲这个案例时老师用v-bind和@input替换v-model,不知道原因,并且后续提到了watch这一options选项,用于监听数据的改变,大致用法:

watch: {
    //这里name是要监听的属性,newValue是更新的值,oldValue是旧的值(可省)
    name(newValue, oldValue){
        
    }
}

父子组件的访问

父组件访问子组件:this.childrenchildren 或 refs reference

  • $children得到的为一个数组类型数据,它包含所有父/子组件对象,实际开发中使用不多

  • $refs默认得到的是一个空对象,用法↓

    <!--在标签中绑定ref属性,指定一个key-->
    <cpn ref="aaa"></cpn>
    ​
    //获取子组件对应的属性数组
    this.$refs.aaa
    

子组件访问父组件:

  • this.parent,和parent,和children类似,不过返回的不是数组类型,但一个组件可在多个父组件中使用,每个父组件的数据可能不同,所以用这种方式获取父组件属性与父组件耦合度过高,很少使用
  • this.$root,访问根组件