VUE-组件通信

第一节、vue中父子组件通信

父组件如何把数据传递给子组件,子组件如何把数据传递给父组件

1 父组件传递参数给子组件,子组件接受参数

父组件:

<字组件标签  k1="v1"    :k2="v2"  

注意:写活就用:
<字组件标签  :k1="v1"   

子组件:

export default{
	props:['k1',......]
}

注意:

props和data、computed同等地位,因此data怎么使用的,props就可以怎么使用\

demo:

Father.vue


<template>
    <div>
        <h1>父组件:</h1>
        <Son :name="name" :user="user"/>
    </div>
</template>

<script>
import Son from './Son.vue'
export default {
    components:{
        Son
    },
    data(){
        return{
            name:"张三",
            user:{
                username:"aaa",
                password:"111"
            }
        }
    },
    methods:{
       
    },
}
</script>
<style>

</style>

Son.vue

<template>
  <div>
    <h2>子组件</h2>
        {{name}} {{user}}
  </div>
</template>

<script>
export default {
    props:["name","user"],
};
</script>

<style>
</style>

解释vue中单向数据流

描述的就是父子组件的通信问题

  • 1 父组件传递给子组件后,如果父组件更新了数据,则子组件能自动同步?
    答:能

  • 2 父组件传递给子组件后,子组件能不能直接修改父组件传递过来值?
    答:不能

2 子组件传递参数给父组件(自定义事件)

子组件能够调用授权后的父组件提供的方法,而调用方法的同时,就能顺便把参数传递给父子、

父组件

<子标签  @自定义事件名="函数"

methods:{
	函数(xx){
		xx就是子组件调用时携带的参数
	}
}

子组件:

this.$emit('自定义事件名',参数)

props的扩展(约束)

    props:{
        对应父组件传递过来的自定义属性:{
        	//必传
            required:true,
            //类型约束
            type:String/Number/Object/Array,
            //默认值
            default:"哈哈"
        }
    },

Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders. Instead, use a data or computed property based on the prop's value. Prop being mutated: "xx"


该错误出现的原因:子组件在偷偷的直接修改props值(父组件传递过来的参数)

第二节、关于父子通信的套路

demo:父子文本框同步问题

1 套餐1: 子组件: data+watch组合

Father.vue

<template>
    <div>
        <h1>父组件</h1>
        <input type="text" v-model="t">
        <hr>
        <Son :t="t"  @change="change"/>
    </div>
</template>

<script>
import Son from './Son.vue'
export default {
    components:{
        Son
    },
    data(){
        return{
            t:""
        }
    },
    methods:{
        change(val2){
            this.t=val2
        }
    }
}
</script>
<style>
</style>

2 Son.vue

<template>
  <div>
    <h1>子组件</h1>
    <input type="text"  v-model="t2">
       
  </div>
</template>

<script>
export default {
    props:["t"],
    data(){
        return{
           t2:""
        }
    },
    watch:{
        t(val){
            console.log("val",val);
            this.t2=val
        },
        t2(val2){
            console.log("val2",val2);
            this.$emit("change",val2)
        }

    }
};
</script>
<style>
</style>

2 套餐2:子组件:computed

son.vue

<template>
  <div>
    <h1>子组件</h1>
    <input type="text"  v-model="t2">
  </div>
</template>

<script>
export default {
    props:["t"],
    computed:{
        t2:{
            get(){
                return this.t
            },
            set(val){
                this.$emit("change",val)
            }
        }
    }
   
  
};
</script>
<style>
</style>

3 套餐3: 利用对象地址来避免单向数据流的规则 (不推荐)

Father.vue

<template>
    <div>
        <h1>父组件</h1>
        <input type="text" v-model="obj.t">
        <hr>
        <Son :obj="obj"  />
    </div>
</template>

<script>
import Son from './Son.vue'
export default {
    components:{
        Son
    },
    data(){
        return{
            obj:{
                 t:"abc"
            }
           
        }
    },
}
</script>
<style>
</style>

Son.vue

<template>
  <div>
    <h1>子组件</h1>
    <input type="text"  v-model="obj.t">
    
  </div>
</template>

<script>
export default {
    props:["obj"],
  
};
</script>


技巧:所有的数据、方法应该都来自于父组件

第三节、事件总线(event bus)

为了方面兄弟组件通信(其实任意关系的两个组件都能够使用bus进行通信)
原理:通过创建一个新的vue实例,作为兄弟组件之间传值的中转站
demo:
有两个兄弟组件:A.vue和B.vue
A组件想要把参数传递给B组件,意味着A组件需要调用B组件的方法,顺带把参数传递过去
B组件(被调用方法者)需要先通过bus注册监听,A组件(调用者)需要通过bus来调用
1 src下新建一个bus.js,编辑

import Vue from 'vue'
let bus=new Vue()
export default bus;

2 被调用者组件需要注册监听(B组件)

需要注意在function中this指向发生了改变,需要通过在改变之前用临时变量that来暂时保管

bus.$on("自定义事件",function(data){//data就是传递过来的值

})
<script>
import bus from '@/bus.js'

export default {

    data(){
        return{
            name:"张三"
        }
    },
    //推荐mounted钩子函数
    mounted(){
        console.log("mounted",this.name);
        let that=this;
        bus.$on("ff",function(data){
            //data就是传递过来的值
            console.log(data);
            console.log("bus",that.name);
        })
    }

}
</script>

3 调用者调用(A组件)

bus.$emit(“对应自定义事件”,参数)

import bus from '@/bus.js'
export default {

    methods:{
        test(){
            bus.$emit("ff",'李四')
        }
    }

}
</script>

练习:把昨天的学生管理操作的 修改渲染功能用bus来实现

第四节、其他通信的方法

1 $parent

 子组件通过this.$parent获取它的父组件,获得之后可以直接操作父组件定义的data、methods等

2 $children

父组件可以通过this.$children获取它的子组件数组,该语法有个弊端(如果有多个儿子,则无法清楚获取具体的某个儿子),因此该语法一般用于父组件只有一个子组件的情况

3 ref和$refs

父组件可以为某些子组件设置ref标记,今后通过this.$refs.标记来获得子组件对象

4 $attrs

爷组件传值给孙组件

Father.vue:

<Son :name="name"/>

Son.vue:
 <Sun v-bind="$attrs"/>

Sun.vue:


<template>
    <div>
        Sun :{{name}}
    </div>
</template>

<script>
export default {
    props:['name']
}
</script>

第五节、插槽 slot

前置

父组件、子组件

概念

在vue中,引入的子组件的标签体是不允许写内容,为了解决这个问题,官方引入了插槽(slot)这个概念

插槽的核心思想:将共性抽取到组件,将不同暴露为插槽,一旦预留了插槽后,就可以让使用者根据自己的需求,决定这个插槽所插入的内容

使用场景 :在复用区域中既有相同的内容,又有不同的内容

注意:拥有都是子组件来开槽,父组件负责传递参数

作用

1 减少了文件个数---》体积变小---》项目性能提升
2 插槽使得组件更具有扩展性

分类:

1 匿名插槽

2 具名插槽

3 后备插槽

4 作用域插槽(难点)

插槽能够接受的内容:

一切内容:可以是数据、也可以使节点

1 匿名插槽

插槽没有名字,可以接受一切内容

Father.vue

<Son>内容</Son>

Son.vue

<slot></slot>

2 备用插槽(默认值)

如果父组件不插入内容,则子组件的插槽默认一个内容

Father.vue

<Son></Son>

Son.vue

<slot>默认值</slot>

3 具名插槽

插槽有名字,只能接受对应名字的内容

Father.vue

<template>
    <div>
        Father
        <Son>
            <template v-slot:s1>
                    a
            </template>

             <template v-slot:s2>
                    b
            </template>
          
        </Son>
        
    </div>
</template>

简写:

v-slot: 可以简写成#

Son.vue

      <slot name="s1"></slot>
      <slot name="s2"></slot>

4 作用域插槽

前三个插槽的共同点:所有的内容由父组件来提供

如果数据在子组件中,因此我们需要把子组件的数据先传递给父组件,父组件拿到数据后和节点绑定完整,再通过插槽插入到子组件,整个过程:作用域插槽

father.vue

<template>
    <div>
        Father
        <Son>
            <template #s1="obj">
                    <a href="obj.myurl">{{obj.myname}}</a>
            </template>
        </Son>
    </div>
</template>

son.vue

<slot name="s1" :myname="name"  :myurl="url"></slot>


  data(){
        return{
           name:"百度",
           url:"http://www.baidu.com"
        }
    },

第六节、面试题:vue中组件通信的方法

父子: props+$emit
兄弟:bus
其他:$parent、$children、$refs+ref
插槽(slot)--属于父子
隔代: $attrs 、provide+inject

provide+inject使用

父组件:


<template>
    <div>
        Father
        <Son></Son>
          
        
    </div>
</template>

<script>
import Son from './Son.vue'
export default {
    components:{
        Son,
    },
    data(){
        return{
            name:"张三",
            age:20
        }
    },
    provide(){
        return{
            name:this.name,
            age:this.age
        }
    }


子/孙组件

<template>
    <div>
        sun
        {{name}}--{{age}}
    </div>
</template>

<script>
export default {
    inject:['name','age']

}
</script>

<style>

</style>

第七节、动态组件

概念和使用

组件切换

语法:

<component :is="子组件对象名"

demo:

Father.vue

<template>
  <div>
    <button @click="current='TabA'">tableA</button>
    <button @click="current='TabB'">tableB</button>
    <button @click="current='TabC'">tableC</button>
    <keep-alive >
         <component :is='current'></component>
    </keep-alive>
  </div>
</template>

<script>
import TabA from "./TableA.vue";
import TabB from "./TableB.vue";
import TabC from "./TableC.vue";
export default {
  components: {
    TabA,
    TabB,
    TabC,
  },
  data(){
    return{
        current:'TabA'
    }
  }
};
</script>

<style>
</style>


注意:引入的组件对象名不能是 TableA,。。。。。。。。。

TableA.vue

<template>
    <div>
        <h1>tableA</h1>
    </div>
</template>

<script>
let timer;
export default {

    created(){
        console.log("A组件创建");

       timer=setInterval(() => {
            console.log("ding");
        }, 1000);
    },
    destroyed(){
        console.log("A组件销毁");
        //清除定时器
        clearInterval(timer)
    }

}
</script>

<style>

</style>

keep-alive

默认情况下,虽则组件的切换(销毁),曾经客户在组件填写的表单内容都会被回收(清空),如果想要保留(缓存这些数据),我们可以使用vue提供的keepAlive容器对指定组件进行缓存(原理就是该组件不会被销毁)

语法:

    <keep-alive>
         <component :is='current'></component>
    </keep-alive>

属性:

include :指定哪些组件被缓存,其余的就不被缓存

   <keep-alive include="TabA,TabB">
         <component :is='current'></component>
    </keep-alive>
    
    
     正则:
    <keep-alive :include="/A/">
         <component :is='current'></component>
    </keep-alive>

exclude: 指定哪些组件不会缓存

    <keep-alive exclude="TabA">
         <component :is='current'></component>
    </keep-alive>

3 如果使用了keep-alive,则可以使用以下两个钩子函数

    //只要进入则触发
    activated(){
        console.log("进入A组件");
    },
    //只要离开则触发
    deactivated(){
        console.log('离开A组件');
    }

name属性

能够为当前组件命令

export default {
	name:"自定义组件名"
}

作用:

  • 1 能够被devtools插件识别
  • 2 支持 <keep-alive include/exclude=“” , include/exclude必须得用name新名字
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值