vue组件传值(8种方法)----props、$emit()、手动封装事件订阅observer、事件总线(Eventbus)、vuex、亲兄弟传值、provide/inject、插槽作用域

 

    1、父传子

        传递:当子组件中在父组件中当做标签使用的时候,给子组件绑定一个自定义属性,值为需要传递的数据
        接收:在子组件内部通过props进行接收,props接收的方式有2种:
            ①通过数组进行接收   props:["属性"]
            ②通过对象进行接收    props:{
                                    属性:{
                                        (1)type:限制数据的类型
                                        (2)default:默认值
                                        (3)required:布尔值,和default二选一
                                    }
                                }
        步骤:
            ①在父组件中给子组件标签上添加自定义属性:
                <son :custom="100"></son>
            ②子组件中通过props接收:
                props:["custom"]
            ③接收到的custom可以直接在标签中使用 {{custom}}
        注意:今后只要看到props就要想到这个属性是用来接收外部数据的。

    2、子传父

        ①接收:当子组件在父组件中当做标签使用的时候,给当前子组件绑定一个自定义事件,值为需要接收值的函数,这个函数不允许加 ()
        ②传递的过程:在子组件内部通过this.$emit("自定义事件名称",需要传递的参数)来进行数据的传递
        步骤:
            ①父组件中给需要接收参数的子组件绑定自定义事件,值为需要接收值的函数:
                <son @handler="handlerMsg"></son>
                methods:{
                    handlerMsg(value){
                        console.log(value)// 这个值是通过this.$emit()触发传来的
                    }
                }
            ②子组件中触发自定义事件:
                this.$emit("handler",100);

    3、非父子传递

        第一种方法:通过给vue原型上添加一个公共的vue实例对象(vue实例对象上有$on()和$emit()),需要传递的一方调用$emit(),需要接收的一方调用$on()。

        步骤:
            ①main.js中:
                Vue.prototype.$observer=new Vue();
            ②需要传递的组件中:
                this.$observer.$emit("handler",100);
            ③需要接收的组件中:
                this.$observer.$on("handler",(value)=>{
                    console.log(value)
                });
                注意:在挂载前(created)进行$on()绑定,先绑定好,再触发。

        *第二种方法:手动封装事件订阅observer

            步骤:
                ①src下新建observer.js:
                    const eventList={};

                    const $on=function (eventName,callback) {  
                        if(!eventList[eventName]){
                            eventList[eventName]=[];
                        }
                        eventList[eventName].push(callback);
                    }

                    const $emit=function(eventName,params){
                        if(eventList[eventName]){
                            let arr=eventList[eventName];
                            arr.forEach((cb)=>{
                                cb(params);
                            });
                        }
                    }

                    const $off=function(eventName,callback){
                        if(eventList[eventName]){
                            if(callback){
                                let index=eventList[eventName].indexOf(callback);
                                eventList[eventName].splice(index,1);
                            }else{
                                eventList[eventName].length=0;
                            }
                        }
                    }

                    export default{
                        $on,
                        $emit,
                        $off
                    }
                ②main.js中用手动封装的observer替代new Vue()
                    import observer from "./observer.js";
                    Vue.prototype.$observer=observer;
                ③在需要传递的组件中用this.$observer.$emit()触发自定义事件:
                    this.$observer.$emit("customHandler","需要传递的值");
                ④在需要接收的组件中用this.$observer.$on()绑定自定义事件:
                    this.$observer.$on("customHandler",this.toggle);





        第三种方法:事件总线(Eventbus)

            步骤:
                ①先创建一个空实例:
                    let bus=new Vue();
                ②通过bus.$on()绑定自定义事件:
                    bus.$on("customHandler",要触发的函数);
                ③通过bus.$emit()来触发自定义事件: 
                    bus.$emit("customHandler");

        *第四种方法:vuex(后续)



        注:如果是亲兄弟:(父传子和子传父)

            步骤:
                ①父组件中声明data数据 state:true ,将state通过props传给其中一个子组件:
                    <two :show="state"></two>
                    props:show
                    此时show的值随着state的变化而变化
                ②再通过另一个子组件去改变父组件的state:
                    标签上绑定自定义事件:
                        <one @customHandler="toggle"></one>
                    再在子组件内部通过$emit()触发customHandler事件:
                        this.$emit("customHandler");



provide / inject(提供/注入)跨组件传值,其实就是父传子


    provide / inject:依赖注入。可以实现跨组件传值,数据的流向只能是向下传递,就是大范围有效的props

    provide:这个配置项必须要在父级进行使用,用来定义后代组件所需要的一些属性和方法。
        语法:
            provide:{

            }
            // 推荐
            provide(){
                return{

                }
            }
    inject:这个配置项必须在后代组件中使用,用来获取根组件定义的跨组件传值的数据。
        语法:
            inject:[] 

            // 推荐
            inject:{
                key:{
                    from:"父组件名称",
                    default:默认值
                }
            }

插槽 slot

    作用:默认情况下组件内部包裹的内容是不会显示的,如果需要进行显示则需要通过插槽来进行显示。

    1、匿名插槽:没有名字的插槽(v-slot:default)

        v-slot
        在组件内部通过<slot></slot>进行接收

        步骤:
            ①App.vue中在组件标签中添加template标签(里面可以写多个标签),写上v-slot属性
                <Header>
                    <template v-slot>
                        <p>111</p>
                        <p>222</p>
                    </template>
                </Header>
            ②在Header.vue组件中通过<slot></slot>开辟一块空间:
                <div class="header">
                    <slot></slot>
                </div>
    

    2、命名插槽:有名字的插槽

        v-slot:slotName
        在组件内部通过<slot name="slotName"></slot>来进行接收

        步骤:
            ①给插槽指令加上名字:
                <template v-slot:slotName>
                    <p>111</p>
                </template>
            ②slot标签添加name属性:
                <div class="header">
                    <slot name="slotName"></slot>
                </div>

            如果还有匿名插槽template,就在Header.vue中用<slot></slot>再开辟一块空间接收匿名插槽。
    

    3、插槽作用域:(子传父)

        v-slot:slotName(名字可写可不写,如果不写默认是default)="变量(这个变量是一个对象)"

        作用:让组件来提供自身需要显示的内容

        步骤:
            ①App.vue中template中设置v-slot="props"(props是一个对象):---------父
                <template v-slot="props">
                    <h2>{{props.info}}</h2>
                </template>
            ②Header.vue中slot标签绑定自定义属性info:----------子,info属性的值提供给父组件中的props.info
                <div class="header">
                    <slot :info="'111'"></slot>
                </div>
            ③在template中可以通过props.info拿到子组件中传来的值
 
            如果要用命名插槽:
                App.vue:直接在v-slot后面加上 :slotName
                Header.vue:<slot name="slotName" :info="'111'"></slot>

















原文地址:https://www.cnblogs.com/wuqilang/p/12341150.html