美文网首页vue
详解Vue.js父子组件通信之Props & $emit

详解Vue.js父子组件通信之Props & $emit

作者: 辉夜真是太可爱啦 | 来源:发表于2020-05-08 09:12 被阅读0次

    1.props

    • 基本使用

    props是父组件传子组件的传参方式,可以看到父组件中传入了一个parentCount变量,通过prop传递给了子组件,子组件拿到的count就是通过prop传递过来的值,所以子组件中显示的1
    // Parent.vue
    <template>
        <div>
            <Child :count="parentCount" />
        </div>
    </template>
    
    <script>
        import Child from "../components/Child";
    
        export default {
            name: "Parent",
            components:{
                Child
            },
            data(){
                return{
                    parentCount:1
                }
            }
        }
    </script>
    
    //Child.vue
    <template>
        <div>{{count}}</div>
    </template>
    
    <script>
        export default {
            name: "Child",
            props:{
                count:Number
            }
        }
    </script>
    
    • 类型限定

    可以看到上面的代码中,给props中的count变量设定了Number的类型限定,如果改为String类型,可以看到如下的报错
    prop传值的类型检测
    可以设置的类型有如下几种类型
    • String
    • Number
    • Boolean
    • Array
    • Object
    • Date
    • Symbol
    • Function
    • Promise
    前面的基本基本类型就不详细讲解了,主要对于Function写一个实际的案例,还是按照上面的案例,做一个点击数字+1的方法吧,也是通过父传子的props方式
    //Parent.vue
    <template>
        <div>
            <Child :parentFunction="addCount" :count="parentCount" />
        </div>
    </template>
    
    <script>
        import Child from "../components/Child";
    
        export default {
            name: "Parent",
            components:{
                Child
            },
            data(){
                return{
                    parentCount:1
                }
            },
            methods:{
                addCount(){
                    this.parentCount++;
                }
            }
        }
    </script>
    
    //Child.vue
    <template>
        <div @click="parentFunction">{{count}}</div>
    </template>
    
    <script>
        export default {
            name: "Child",
            props:{
                count:Number,
                parentFunction:Function
            }
        }
    </script>
    
    • 类型限定-进阶

    不仅能传变量,还能传递方法,能对于变量的数据类型加以控制,当然,props远比你想象的更强大,他不仅可以传入一个字符串,数组,还能传入一个对象,在对象中可以进行设置必填,设置默认值,自定义校验等操作
    export default {
        name: "Child",
        props:{
             //你可以让count不仅可以传数值型,还能传入字符串
            count:[Number,String],   
            //设置必填
            count:{
                type:Number,
                require:true 
            }, 
            //设置默认值
            count:{
                type:Number,
                default:100  
            },
            //设置带有默认值的对象,对象或数组默认值必须从一个工厂函数获取
            user:{           
                type:Object,
                default: ()=>{return {name:'jj'}}
            },
            // 自定义校验,这个值必须匹配下列字符串中的一个
            user:{
                type:String,
                validate: (value)=>{return ['bob','jack','mary'].findIndex(value)!==-1}
            }
        }
    }
    
    • 单向数据流

    prop还有一个特点,是单向数据流,你可以理解为自来水从上流至下,父组件中值的变化能传递到子组件中更新,反之,子组件中的更新是不会触发父组件的更新的,这样可以防止从子组件意外改变父级组件的状态,从而导致你的应用的数据流向难以理解。

    //Parent.vue
    <template>
        <div>
            <div>父级别{{parentCount}}</div>
            <Child :count="parentCount" />
        </div>
    </template>
    
    <script>
        import Child from "../components/Child";
    
        export default {
            name: "Parent",
            components:{
                Child
            },
            data(){
                return{
                    parentCount:1
                }
            },
            methods:{
    
            }
        }
    </script>
    
    //Child.vue
    <template>
        <div>{{count}}
            <button @click="addCount">测试</button>
        </div>
    </template>
    
    <script>
    export default {
        name: "Child",
        props:{
            count:Number,
        },
        methods:{
            addCount(){
                this.count+=1;
            }
        }
    }
    </script>
    
    上面的子组件中,点击按钮,改变count,子组件的数值会进行累加,但是会发生报错,同时,父组件的value值并不会发生更新,这就是因为props是单向数据流的,至于如何实现双向数据流,让子组件的更新能同时更新父组件,在接下来的讲解中,我会揭开它的面纱
    props的单向数据流

    2. $emit

    • 基本使用

    • $emit是子传父的通信方式,官方说法是触发当前实例上的事件。附加参数都会传给监听器回调,$emit接收两个参数,第一个是事件名,你可以理解为click,change等事件监听的事件名,然后呢,这个事件名是绑定在父组件当中的,第二个参数就是传递的参数啦,话不多说,上个栗子瞅瞅
    //Parent.vue
    <template>
        <div>
            <Child @childListener="getChildValue" />
        </div>
    </template>
    
    <script>
        import Child from "../components/Child";
    
        export default {
            name: "Parent",
            components:{
                Child
            },
            data(){
                return{
    
                }
            },
            methods:{
                getChildValue(value){
                    console.log(value);
                }
            }
        }
    </script>
    
    //Child.vue
    <template>
        <div>
            <button @click="addCount">测试</button>
        </div>
    </template>
    
    <script>
    export default {
        name: "Child",
        methods:{
            addCount(){
                this.$emit('childListener','test');
            }
        }
    }
    </script>
    
    子组件点击提交的时候,相当于触发了父组件的自定义事件,父组件能够在自定义事件中获取到子组件通过$emit传递的值,所以,当子组件的按钮点击的时候,控制台会打印出test
    • 父子组件双向绑定

    • 1.props结合$emit方式实现双向绑定
    现在,让我们再次回到之前描述的单向数据流的场景中,由于有的时候可能因为项目需要,确实需要实现双向的数据流绑定,可以看到依旧是单向数据流的方式,父组件的parentCount通过子组件的props进行值的传递,子组件点击按钮的时候,触发父组件的自定义事件,改变父组件的值(进行累加操作),然后父组件通过props,将更新传递到子组件,实现了父子组件的双向数据绑定。
    //Parent.vue
    <template>
        <div>
            <div>父级别{{parentCount}}</div>
            <Child @update:count="getValue" :count="parentCount" />
        </div>
    </template>
    
    <script>
        import Child from "../components/Child";
    
        export default {
            name: "Parent",
            components:{
                Child
            },
            data(){
                return{
                    parentCount:1
                }
            },
            methods:{
                getValue(value){
                    this.parentCount=value;
                }
            }
        }
    </script>
    
    //Child.vue
    <template>
        <div>{{count}}
            <button @click="addCount">测试</button>
        </div>
    </template>
    
    <script>
    export default {
        name: "Child",
        props:{
            count:Number,
        },
        methods:{
            addCount(){
                this.$emit('update:count',this.count+1);
            }
        }
    }
    </script>
    
    • 2.使用.sync修饰符
    你可以觉得上面的写法有点长,那么,你可以使用一个vue 的语法糖(指在不影响功能的情况下,添加某种方法实现同样的效果,从而方便程序开发,例如v-bindv-on,可以改写为:以及@),那么,我们下面就用.sync修饰符来重写父组件吧,子组件的写法依旧不变,实际运行发现效果是一样的
    <template>
        <div>
            <div>父级别{{parentCount}}</div>
            <Child :count.sync="parentCount" />
        </div>
    </template>
    
    <script>
        import Child from "../components/Child";
    
        export default {
            name: "Parent",
            components:{
                Child
            },
            data(){
                return{
                    parentCount:1
                }
            },
        }
    </script>
    

    相关文章

      网友评论

        本文标题:详解Vue.js父子组件通信之Props & $emit

        本文链接:https://www.haomeiwen.com/subject/mgsxnhtx.html