组件通讯-非父子,slot插槽

组件通讯-非父子,slot插槽

组件通讯-非父子

非父子组件之间通过一个空的Vue实例来传递数据。

1
const bus = new Vue();   //bus:公交车  事件总线
  • 核心逻辑
1
2
3
4
5
组件A给组件B传值:
1. 创建一个bus对象
2. 组件a触发事件,给组件b发送数据
3. 组件b给bus对象注册事件
4. 组件b提供函数,用于接收数据
  • 组件A触发bus的事件
1
2
3
4
5
6
7
<button @click="send">表白</button>

methods: {
send() {
bus.$emit("get", this.msg);
}
}
  • 组件B给bus注册事件
1
2
3
4
5
6
7
 //rose在组件创建的时候,给bus注册了一个事件
created () {
bus.$on("get", (msg)=>{
console.log("这是rose注册的事件", msg);
this.msg = msg;
});
}
  • 组件B通过事件处理程序可以获取到传递的值
1
2
3
4
bus.$on("get", (msg)=>{
console.log("这是rose注册的事件", msg);
this.msg = msg;
});

注意点:1. 传递和接受数据的事件必须在同一个总线上 2. 注册的事件和触发的事件必须保持一致

bus是一种通用的组件通讯方案

现在有三种组件通讯的方案

1
2
3
4
1. 父传子
2. 子传父
3. 非父子(bus)
其实bus方案也适用于父传子和子传父的方案

slot插槽

当组件中某一项需要单独定义,那么就应该使用slot

Vue 实现了一套内容分发的 API,将 <slot>元素作为承载分发内容的出口。

匿名插槽slot

除非子组件模板包含至少一个 <slot> 插口,否则父组件的内容将会被丢弃 ,当子组件模板只有一个没有属性的 slot 时,父组件整个内容片段将插入到 slot 所在的 DOM 位置,并替换掉 slot 标签本身。

在组件的模版中定义slot插槽

1
2
3
4
5
6
7
8
9
10
11
Vue.component("modal", {
template: `
<div class="modal">
<p>温馨提示</p>
<div>
<slot></slot>
</div>
<button>关闭</button>
</div>
`,
});

父组件传值

1
2
3
4
<modal>
<h3>你确定要退出系统吗?</h3>
</modal>
<modal>你确定要删除这个内容吗?</modal>

具名插槽

如果一个组件中想使用多个slot那么此时就应该使用具名插槽。

使用方法

  1. 给插槽添加name属性
  2. 给插入内容添加slot属性,属性值和插槽的name属性值相同
1
2
3
4
5
6
7
8
9
Vue.component("modal", {
template: `
<div class="modal">
<slot name="header"></slot>
<slot name="content"></slot>
<slot name="footer"></slot>
</div>
`,
});
1
2
3
4
5
6
7
8
9
10
11
<modal>
<template v-slot:header>
温馨提示
</template>
<template v-slot:content>
你要删除内容吗
</template>
<template v-slot:footer>
<button>关闭</button>
</template>
</modal>

作用域插槽

在分发内容时,如果需要用到子组件内的数据,需要用到作用域插槽

作用域插槽的使用

  1. 给插槽添加name属性和自定义属性
  2. 将插入内容用template标签包裹起来,给template标签添加v-slot: 属性值="obj",属性值和插槽的name属性值相同。(template只用来分块,不会渲染,具名插槽也可以使用)
  3. 自定义属性和属性值会自动添加到一个对象中,这个对象可以通过上面的obj取到
1
2
3
4
5
6
7
8
9
Vue.component('modal', {
template: `
<div>
<h3><slot name="title"></slot></h3>
<p><slot name="content"></slot></p>
<slot name="confirm" value="确定"></slot>
</div>
`
})
1
2
3
4
5
6
7
8
9
10
11
<modal>
<template v-slot:title>温馨提示</template>
<template v-slot:content>你确定也要退出了</template>
<template v-slot:confirm="scope">
<!-- 若没有传参,那么这个scope会取父组件内的数据 -->
<button href="#">{{scope.value}}</button>
</template>
<template v-slot:cancel="scope">
<button href="#">{{scope.value}}</button>
</template>
</modal>

没有指定v-slot的内容会给匿名插槽或v-slot: default