vue-day04----組件傳值、provide/inject、插槽(slot)、動態組件、keep-alive、directive

### 組件傳值

    一、父傳子
        傳遞:當子組件中在父組件中當作標籤使用的時候,給子組件綁定一個自定義屬性,值爲須要傳遞的數據
        接收:在子組件內部經過props進行接收,props接收的方式有2種:
            ①經過數組進行接收   props:["屬性"]
            ②經過對象進行接收    props:{
                                    屬性:{
                                        (1)type:限制數據的類型
                                        (2)default:默認值
                                        (3)required:布爾值,和default二選一
                                    }
                                }
        步驟:
            ①在父組件中給子組件標籤上添加自定義屬性:
                <son :custom="100"></son>
            ②子組件中經過props接收:
                props:["custom"]
            ③接收到的custom能夠直接在標籤中使用 {{custom}}
        注意:從此只要看到props就要想到這個屬性是用來接收外部數據的。




    二、子傳父
        ①接收:當子組件在父組件中當作標籤使用的時候,給當前子組件綁定一個自定義事件,值爲須要接收值的函數,這個函數不容許加 ()
        ②傳遞的過程:在子組件內部經過this.$emit("自定義事件名稱",須要傳遞的參數)來進行數據的傳遞
        步驟:
            ①父組件中給須要接收參數的子組件綁定自定義事件,值爲須要接收值的函數:
                <son @handler="handlerMsg"></son>

 

                methods:{
                    handlerMsg(value){
                        console.log(value)// 這個值是經過this.$emit()觸發傳來的
                    }
                }
            ②子組件中觸發自定義事件:
                this.$emit("handler",100);

 

    三、非父子傳遞
        第一種方法:經過給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

    做用:默認狀況下組件內部包裹的內容是不會顯示的,若是須要進行顯示則須要經過插槽來進行顯示。

 

    一、匿名插槽:沒有名字的插槽(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>
    
    二、命名插槽:有名字的插槽
        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>再開闢一塊空間接收匿名插槽。
    
    三、插槽做用域:(子傳父)
        v-slot:slotName(名字可寫可不寫,若是不寫默認是default)="變量(這個變量是一個對象)"

 

        做用:讓組件來提供自身須要顯示的內容

 

        步驟:
            ①App.vue中template中設置v-slot="props"(props是一個對象):
                <template v-slot="props">
                    <h2>{{props.info}}</h2>
                </template>
            ②Header.vue中slot標籤綁定自定義屬性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>



`以上都是組件傳值`



### 動態組件

    經過vue的內置組件components的is屬性來動態的切換頁面

 

    is的值是哪一個組件就會顯示哪一個組件,通常is前面有冒號表示動態組件。

 

    步驟:
        ①在Mine.vue中,在組件配置項中添加name屬性:
            export default{
                name:Mine
            }
        ②App.vue中設置data屬性,用一個變量componentName接收name:
            export default{
                data(){
                    return{
                        componentName:"Mine"
                    }
                }
            }
            而後在component標籤中添加is屬性爲變量componentName,就會渲染Mine組件:
            <component :is="componentName"></component>
    
  注意:component標籤不顯示在頁面上
 
    場景:不在意瀏覽器地址的時候能夠用動態組件,如選項卡

 

### keep-alive

    keep-alive是vue的內置組件,用來包裹動態切換到路由或者組件,能夠防止組件頻繁的進行建立和銷燬,從而達到性能優化的效果,當組件被keep-alive包裹的時候會增長兩個生命週期:
         activated----活躍狀態,進入的時候觸發,能夠進行數據請求
         deactivated----緩存狀態,離開的時候觸發

 

    使用:
        <keep-alive>
            <component :is="componentName"></component>
        </keep-alive>
        正常的組件顯示會顯示建立前、建立後、掛載前、掛載後4個生命週期。在切換時會經歷當前組件的建立前、建立後、掛載前,上一個組件的銷燬前和銷燬後,再進行當前組件的掛載後,共6個生命週期。
        使用keep-alive包裹後,切換組件的時候,會直接經歷當前組件的建立前、建立後、掛載前、掛載後,共4個生命週期,而省去了上一個組件的銷燬前和銷燬後。當全部的組件都經歷了建立和掛載後,就所有儲存在緩存裏,以後進行的切換都是在緩存中拿數據。
        在當前組件mounted的先後分別是上一個組件的deactivated和當前組件的activated。deactivated和activated每次都會切換都會觸發,因此數據請求放在activated中。

 

    屬性:
        include----包括,須要被緩存的組件(字符串、正則)
        exclude----排除,不須要被緩存的組件(實時更新的組件)(字符串、正則)
        max----最多能被緩存多少個組件,項目中組件特別多的時候即便用了include也會形成緩存壓力,就用max規定下最多能夠緩存幾個,超過該值後面的會將前面的替代掉,會從新走一遍生命週期流程(Number)

 

    注意:
        一、include和exclude不能同時使用,若是使用正則,屬性前加冒號
        二、實時更新的組件不要用keep-alive

 

### 自定義指令  directive

 

    全局自定義指令:Vue.directive()
    局部自定義指令:directives

 

    directive(參數一,參數二)
        參數一:指令名稱
        參數二:指令的配置項,能夠是函數,也能夠是對象
            函數:
                參數一:使用當前指令的元素
                參數二:指令的詳細信息
                    {
                        modifiers:修飾符(只要自定義指令後面跟了修飾符,modifiers對象中就有值,爲true),
                        value:指令的值(假設指令這樣寫:<div v-test="'aaa'"></div>,那麼value就是aaa)
                    }
                    
    
    指令的做用:操做DOM元素

 

    步驟:
        ①src下新建utils/utils.js:
            import Vue from "vue";


            /**
            *  v-test指令:
            *      <div v-test="'發發發'"></div>
            *      至關於
            *      <div>發發發</div>
            * 
            */
            Vue.directive("test",(el,{value})=>{
                el.innerText=value;
            });


            /**
            *  設置背景顏色的指令 
            * 
            */
            Vue.directive("backgroundColor",(el,{value,...rest})=>{
                el.style.backgroundColor=value;
            });


            /**
            *  阻止瀏覽器默認事件:v-event.prev
            * 
            */
            Vue.directive("event",(el,{modifiers})=>{
                let {prev}=modifiers;
                el.addEventListener("contextmenu",(e)=>{
                    if(prev){
                        e.preventDefault();
                    }
                });
            });
            
            /**
            *  自動聚焦
            * 
            */
            Vue.directive("focus",{
                inserted(el){
                    el.focus();
                }
            });
        ②main.js中引入:
            import "./utils/utils.js";
        ③App.vue中使用自定義指令:
            <div v-test="'發發發'" v-backgroundColor.not="'blue'"></div>
            <div v-test="'阻止瀏覽器默認事件'" v-backgroundColor="'yellow'" v-event.prev></div>
            <input type="text" v-focus>
相關文章
相關標籤/搜索