文章

Vue3基础——组件通信

props传参

通常用于父组件和子组件的通信

  • 在子组件中定义props,使用props
  • 在父组件中传递参数
  • 子组件向父组件传递需要使用回调的方式

子组件中定义props

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<script setup lang="ts">
import {ref} from "vue";

// 定义props
defineProps(['value1', 'value2', 'getValue3']);

let value3 = ref('value3');
</script>

<template>
  <div>{ {value1} }</div>
  <div>{ {value2} }</div>
  <!--调用回调,传递value3-->
  <button @click="getValue3(value3)">向父组件传递value3</button>
</template>

在父组件中传递参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<script setup lang="ts">
import {ref} from 'vue';
import Inner from "@/components/Inner.vue";

let value1 = ref('value1');
let value2 = ref('value2');

let value3 = ref('');

// 回调函数
function getValue3(value: string) {
  value3.value = value;
}

</script>

<template>
  <div>
    <div>{ {value3} }</div>
    <!--传参-->
    <Inner :value1="value1" :value2="value2" :getValue3="getValue3"></Inner>
  </div>
</template>

自定义事件

主要用于父组件向子组件通信

  • 在子组件中定义自定义事件,触发事件
  • 在父组件中传递事件回调

在子组件中定义自定义事件,触发事件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<script setup lang="ts">
import {ref} from "vue";

let value = ref('value');

// 通过emit对象触发事件
const emit = defineEmits(['get-value']);

</script>

<template>
  <!--传入触发的事件名和参数-->
  <button @click="emit('get-value', value)">向父组件传递value</button>
</template>

在父组件中传递事件回调

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<script setup lang="ts">
import {ref} from 'vue';
import Inner from "@/components/Inner.vue";

let value1 = ref('');

function getValue(value: string) {
  value1.value = value;
}

</script>

<template>
  <div>
    <div>{ {value1} }</div>
    <!--自定义事件传入回调-->
    <Inner @get-value="getValue"></Inner>
  </div>
</template>

mitt消息总线

使用前安装mitt:npm i mitt

初始化消息总线emitter

1
2
3
import mitt from "mitt";
const emitter = mitt();
export default emitter;

emitter对象主要使用四个成员

  • all:获取所有事件,返回事件和对应回调的map
  • on():绑定事件
  • emit():触发事件
  • off():注销事件

子组件接收value1,传递value2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<script setup lang="ts">
import {ref} from "vue";
import emitter from "@/utils/emitter";

let value1 = ref('');

emitter.on('get-value1', (value) => {
  if (typeof value === 'string') {
    value1.value = value;
  }
})

</script>

<template>
  <div>{ {value1} }</div>
  <button @click="emitter.emit('get-value2', 'value2')">触发get-value2</button>
</template>

父组件接收value2,传递value1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<script setup lang="ts">
import {ref} from 'vue';
import Inner from "@/components/Inner.vue";
import emitter from "@/utils/emitter";

let value2 = ref('');

emitter.on('get-value2', (value) => {
  if (typeof value === 'string') {
    value2.value = value;
  }
})

</script>

<template>
  <div>
    <div>{ {value2} }</div>
    <button @click="emitter.emit('get-value1', 'value1')">触发get-value1</button>
    <Inner></Inner>
  </div>
</template>

在组件取消挂载时注销事件

1
2
3
onUnmounted(() => {
  emitter.off('get-value1')
})

$attrs

用于父组件向子组件通信,在父组件传递参数时,若子组件未定义对应的props,则参数保存在$attrs对象中

父组件传递参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<script setup lang="ts">
import {ref} from 'vue';
import Inner from "@/components/Inner.vue";

let value1 = ref('value1')
let value2 = ref('value2');

</script>

<template>
  <div>
    <Inner :value1="value1" :value2="value2"></Inner>
  </div>
</template>

子组件中未定义为props的参数会以键值对的形式保存到$attrs对象中

1
2
3
4
5
6
7
8
9
10
11
12
13
<script setup lang="ts">
// value1定义为props,value2未定义,value2保存在$attrs对象中
defineProps(['value1']);
</script>

<template>
  <!--
  value1
  { "value2": "value2" }
  -->
  <div>{ {value1} }</div>
  <div>{ {$attrs} }</div>
</template>

ref标签属性

ref标签属性可以获取组件的实例对象或HTML元素的DOM对象

  • 子组件定义暴露的数据
  • 父组件通过ref属性获取对象,获取暴露的数据

$refs$parent

  • $refs:以键值对的形式存储所有使用ref属性的元素对象
  • $parent:当前组件的父组件对象

子组件中定义暴露的数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<script setup lang="ts">
import { ref } from 'vue'

const name = ref("张三")

const sayName = ()=>{
  console.log("我叫 " + name.value)
}

// 使用defineExpose函数定义暴露的数据
defineExpose({name, sayName});
</script>

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

父组件通过ref属性获取子组件对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<script setup lang="ts">
import {onMounted, ref} from 'vue';
import Inner from "@/components/Inner.vue";

let inner = ref();

// 在父组件挂载完成后使用子组件对象
onMounted(() => {
  console.log(inner.value.name);
  inner.value.sayName();
});

</script>

<template>
  <div>
    <Inner ref="inner"></Inner>
  </div>
</template>

provide与inject

用于祖先组件向子组件提供数据

  • 在祖先组件中使用provide提供数据
  • 在子组件中使用inject获取数据

在祖先组件中提供数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<script setup lang="ts">
import {provide, ref} from 'vue';
import Inner from "@/components/Inner.vue";

let value1 = ref('value1');

// 传入key和value
provide('key1', value1);

</script>

<template>
  <div>
    <Inner></Inner>
  </div>
</template>

在子组件中获取数据

1
2
3
4
5
6
7
8
9
10
11
<script setup lang="ts">
import {inject} from 'vue';

// 第二个参数为默认值,可辅助ts类型推断
let value1 = inject('key1', 'defaultValue');

</script>

<template>
  <div>{ {value1} }</div>
</template>
本文由作者按照 CC BY 4.0 进行授权