vue-day04----组件传值、provide/inject、插槽(slot)、动态组件、keep-alive、directive

### 组件传值

    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:
                <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)
    注意:
        1、include和exclude不能同时使用,如果使用正则,属性前加冒号
        2、实时更新的组件不要用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>









猜你喜欢

转载自www.cnblogs.com/wuqilang/p/12359535.html