非父子间的组件通信
分为两种方式
1.Provide/Inject
专门给子孙用的,兄弟不行
爷孙之间用props就会很麻烦,通过provide和Inject就可以避免这么麻烦。
App.vue
<template>
</template>
<script>
ipmort Home from './Home.vue'
import { computed } from 'vue'
export default{
components:{
Home
},
//1.provide:开始为别人提供数据
provide:{
最好默认写成函数形式,也就是return{}
//1.使用return,否则this指向有问题
return{
name:"why",
age:18,
//2.想拿到一个对象数据,在provide必须使用return
length:this.names.length
//这里length不是响应式的,names数组长度改变是,length其实是不变的
//后期会告诉为什么这样做,就能变成响应式
length:computed(()=> this.names.length)
}
},
data(){
return{
names:["abc","cba"]
}
}
}
</script>
length讲解:computed一般会传递一个getter函数,所以直接写箭头函数就行;这里的this就是想找provide中的this
Home.vue
<template>
</template>
<script>
ipmort HomeContent from './HomeContent.vue'
</script>
HomeContent.vue
<template>
<div>
这里length其实是ref对象,具体的值要通过value
{{name}}--{{age}}---{{length.value}}
</div>
</template>
<script>
export default{
//2.使用provide提供的数据,就需要inject注入
inject:['name','age']
}
</script>
以上是组件之间数据的传输,可是我想要组件间,非连接的组件之间的,事件的传递,那么就使用全局事件总线!
2.Mitt全局事件总线库
npm install mitt
其次可以进行封装
eventbus.js
//mitt实质是一个函数
import mitt from 'mitt'
const emitter = mitt();
export default emitter;
App.vue
<template>
</template>
<script>
import Home from './Home.vue'
import About from './About.vue'
export default{
components:{
Home,
About,
}
}
</script>
Home
<template>
</template>
<script>
import
export default{
}
</script>
About
<template>
<div>
<button @click="btnClick"/>
</div>
</template>
<script>
import emmiter from './eventbus'
export default{
components:{
},
methods:{
btnClick(){
emmiter.emit("why",{name:"why",age:"18"})
console.log('我是About')
}
}
}
</script>
HomeContent.vue
<template>
</template>
<script>
import emitter from './eventbus'
export default{
一开始创建的时候我就监听函数
created(){
emitter.on("why",(info)=>{
console.log('我是HomeContent')
})
}
}
</script>
在About中通过emitter发送了一个事件,HomeContent中监听
当我点击About中的click时,我的HomeContent也会触发事件
取消emitter中所有的监听
emitter.all.clear()
实际上,我们更推荐Vuex来进行组件间的通信
认识插槽Slot
如何使用插槽slot?
App.vue
<template>
<div>
这个时候,MySlot的位置就变成了一个按钮,也可以插入组件
<my-slot-cpn>
<button>我是按钮</button>
</my-slot-cpn>
</div>
</template>
<script>
import MySlotCpn from './MySlotCpn.vue'
export default{
components:{
MySlotCpn,
}
}
</script>
MySlotCpn.vue
<template>
<h2>组件开始</h2>
//由外界决定我要显示什么,先占一个坑,预留插槽
<slot></slot>
<h2>组件结束</h2>
</template>
<script>
import
export default{
}
</script>
插槽的默认内容
当我没有传给插槽内容时,插槽可以定义默认元素
<my-slot-cpn></my-slot-cpn>
<slot>
<i>我是默认元素,当我my-slot-cpn插入数据时,我的i元素就会消失</i>
</slot>
当我在插槽里定义了很多数据,一个坑位就能把所有的数据全部展示
<slot></slot>
但是如果我定义了很多数据,也占了很多坑位,那么每个坑位都会显示数据,所以需要我们手工指定具体给哪个坑位。也就是具名插槽
具名插槽的使用
必须在template标签里书写
v-slot:插槽里写的name的值
这样每个插槽都有自己需要的数据了
有些时候,我插槽里的name不是写死的,而且通过配置决定插槽的名字
App.vue
<nav-bar :name="name">
//v-slot:name表示取 名叫name的插槽,并不会取值,所以要用[]表示取值
<template v-slot:[name]>
<i>我是传数据的,NavBar里是占坑的</i>
</template>
</nav-bar>
data(){
return{
name:"why"
}
}
NavBar.vue
<slot :name="name"></slot>
props:{
接收父组件传来的name值是why
name:String
}
具名插槽v-slot的简写:#
作用域插槽的使用
认识作用域插槽
v-slot="slotProps",slotProps就是坑位里写的属性
子组件
父组件
如果插槽有name,name就要指定名字
<slot name="why">
独占默认插槽的缩写
当只有一个插槽占坑时,并且不是具名插槽,就可以删除template
完整前:
简写后: