当前位置:   article > 正文

Vue3组件之间通信方式

Vue3组件之间通信方式

1.props 自定义属性

           实现父子组件通信,过defineProps获取父组件传递的数据

1.父组件给子组件传递数据
  1. <template>
  2. <div class="box">
  3. <h1>props:我是父组件曹操</h1>
  4. <hr />
  5. <Child info="我是曹操" :money="money" :shy="shy"></Child>
  6. </div>
  7. </template>
  8. <script setup lang="ts">
  9. //props:可以实现父子组件通信,props数据还是只读的!!!
  10. import Child from './Child.vue'
  11. import { ref } from 'vue'
  12. let money = ref(10000)
  13. let shy = ref<string>('说话啊!')
  14. </script>
  15. <style scoped>
  16. .box {
  17. width: 100vw;
  18. height: 400px;
  19. background: yellowgreen;
  20. }
  21. </style>
2.子组件获取父组件传递数据
  1. <template>
  2. <div class="son">
  3. <h1>我是子组件:曹植</h1>
  4. <p>{{props.info}}</p>
  5. <p>{{props.money}}</p>
  6. <!--props可以省略前面的名字--->
  7. <p>{{info}}</p>
  8. <p>{{money}} -- {{ shy}}</p>
  9. <button @click="updateProps">修改props数据</button>
  10. </div>
  11. </template>
  12. <script setup lang="ts">
  13. //需要使用到defineProps方法去接受父组件传递过来的数据
  14. //defineProps是Vue3提供方法,不需要引入直接使用
  15. // 第一种接受方式
  16. // let props = defineProps(['info','money']); 返回代理对象
  17. // 第二种接受方式
  18. let props = defineProps({
  19. shy: {
  20. type: Number,
  21. default: 0
  22. },
  23. info: {
  24. type: String,
  25. default: '我是曹植'
  26. },
  27. money: {
  28. type: Number,
  29. default: 1000
  30. }
  31. })
  32. //按钮点击的回调
  33. const updateProps = () => {
  34. // props.money+=10; props:只能读
  35. console.log(props.info)
  36. }
  37. </script>
  38. <style scoped>
  39. .son {
  40. width: 400px;
  41. height: 200px;
  42. background: hotpink;
  43. }
  44. </style>

2自定义事件

实现子组件向父组件传递数据

Event1子组件

  1. <template>
  2. <div class="son">
  3. <p>我是子组件1</p>
  4. <!-- 父组件绑定事件@click作用在跟节点上的 -->
  5. <button>点击我也执行</button>
  6. </div>
  7. </template>
  8. <script setup lang="ts">
  9. </script>
  10. <style scoped>
  11. .son {
  12. width: 400px;
  13. height: 200px;
  14. background: skyblue;
  15. }
  16. </style>

Event2子组件

  1. <template>
  2. <div class="child">
  3. <p>我是子组件2</p>
  4. <button @click="handler">点击我触发自定义事件xxx</button>
  5. <button @click="$emit('click','AK47','J20')">点击我触发自定义事件click</button>
  6. </div>
  7. </template>
  8. <script setup lang="ts">
  9. //利用defineEmits方法返回函数触发自定义事件
  10. let $emit = defineEmits(['xxx', 'click']) 返回一个$emit方法
  11. //按钮点击回调
  12. const handler = () => {
  13. //第一个参数:事件类型 第二个|三个|N参数即为注入数据
  14. $emit('xxx', '东风导弹', '航母')
  15. }
  16. </script>
  17. <style scoped>
  18. .child {
  19. width: 400px;
  20. height: 200px;
  21. background: pink;
  22. }
  23. </style>

EventText父组件

正常说组件标签书写@click应该为原生DOM事件,但是如果子组件内部通过defineEmits定义就变为自定义事件了

  1. <template>
  2. <div>
  3. <h1>自定义事件</h1>
  4. <!--
  5. vue2框架当中:这种写法自定义事件,通过.native变为原生DOM事件
  6. vue3框架这种写法为原生DOM事件,是作用在子组件的根节点上
  7. -->
  8. <Event1 @click="handler1"></Event1>
  9. <hr>
  10. <!-- 绑定自定义事件xxx:实现子组件给父组件传递数据 -->
  11. <Event2 @xxx="handler2" @click="handler3"></Event2>
  12. </div>
  13. </template>
  14. <script setup lang="ts">
  15. //引入子组件
  16. import Event1 from './Event1.vue'
  17. //引入子组件
  18. import Event2 from './Event2.vue'
  19. //事件回调---1
  20. const handler1 = () => {
  21. console.log(123)
  22. }
  23. //事件回调---2
  24. const handler2 = (param1, param2) => {
  25. console.log(param1, param2)
  26. }
  27. //事件回调--3
  28. const handler3 = (param1, param2) => {
  29. console.log(param1, param2)
  30. }
  31. </script>
  32. <style scoped>
  33. </style>

3全局事件总线(订阅发布模式)

全局事件总线可以实现任意组件通信,通过插件mitt实现。

Mitt官网地址

src/bus/index.ts

  1. //引入mitt插件:mitt一个方法,方法执行会返回bus对象
  2. import mitt from 'mitt';
  3. const $bus = mitt();
  4. export default $bus;

child1.vue

  1. <template>
  2. <div class="child1">
  3. <h3>我是子组件1:曹植</h3>
  4. </div>
  5. </template>
  6. <script setup lang="ts">
  7. import $bus from "../../bus";
  8. import { onMounted } from "vue";
  9. //组件绑定一个事件,接受兄弟组件传递的数据
  10. onMounted(() => {
  11. //第一个参数:即为事件类型 第二个参数:即为事件回调
  12. $bus.on("car", (car) => {
  13. console.log(car);
  14. });
  15. });
  16. </script>
  17. <style scoped>
  18. .child1 {
  19. width: 300px;
  20. height: 300px;
  21. background: hotpink;
  22. }
  23. </style>

Childe2.vue

  1. <template>
  2. <div class="child2">
  3. <h2>我是子组件2:曹丕</h2>
  4. <button @click="handler">点击我给兄弟送一台法拉利</button>
  5. </div>
  6. </template>
  7. <script setup lang="ts">
  8. //引入$bus对象
  9. import $bus from '../../bus';
  10. //点击按钮回调
  11. const handler = ()=>{
  12. $bus.emit('car',{car:"法拉利"});
  13. }
  14. </script>
  15. <style scoped>
  16. .child2{
  17. width: 300px;
  18. height: 300px;
  19. background: skyblue;
  20. }
  21. </style>

4.v-model

 v-model可以收集表单数据(数据双向绑定),还可以实现父子组件数据同步。

利用props[modelValue]与自定义事件[update:modelValue]实现的

child.vue

  1. <template>
  2. <div class="child">
  3. <h3>钱数:{{ modelValue }}</h3>
  4. <button @click="handler">父子组件数据同步</button>
  5. </div>
  6. </template>
  7. <script setup lang="ts">
  8. //接受props
  9. let props = defineProps(["modelValue"]);
  10. let $emit = defineEmits(['update:modelValue']);
  11. //子组件内部按钮的点击回调
  12. const handler = ()=>{
  13. //触发自定义事件
  14. $emit('update:modelValue',props.modelValue+1000);
  15. }
  16. </script>
  17. <style scoped>
  18. .child {
  19. width: 600px;
  20. height: 300px;
  21. background: skyblue;
  22. }
  23. </style>

child1.vue

  1. <template>
  2. <div class="child2">
  3. <h1>同时绑定多个v-model</h1>
  4. <button @click="handler">pageNo{{ pageNo }}</button>
  5. <button @click="$emit('update:pageSize', pageSize + 4)">
  6. pageSize{{ pageSize }}
  7. </button>
  8. </div>
  9. </template>
  10. <script setup lang="ts">
  11. let props = defineProps(["pageNo", "pageSize"]);
  12. let $emit = defineEmits(["update:pageNo", "update:pageSize"]);
  13. //第一个按钮的事件回调
  14. const handler = () => {
  15. $emit("update:pageNo", props.pageNo + 3);
  16. };
  17. </script>
  18. <style scoped>
  19. .child2 {
  20. width: 300px;
  21. height: 300px;
  22. background: hotpink;
  23. }
  24. </style>

ModelTest.vue

  1. <template>
  2. <div>
  3. <h1>v-model:钱数{{ money }}{{pageNo}}{{pageSize}}</h1>
  4. <input type="text" v-model="info" />
  5. <hr />
  6. <!-- props:父亲给儿子数据 -->
  7. <!-- <Child :modelValue="money" @update:modelValue="handler"></Child> -->
  8. <!--
  9. v-model组件身上使用
  10. 第一:相当给子组件传递props[modelValue] = 10000
  11. 第二:相当给子组件绑定自定义事件update:modelValue
  12. -->
  13. <Child v-model="money"></Child>
  14. <hr />
  15. <Child1 v-model:pageNo="pageNo" v-model:pageSize="pageSize"></Child1>
  16. </div>
  17. </template>
  18. <script setup lang="ts">
  19. //父亲给子组件数据 props
  20. //子组件给父组件数据 自定义事件
  21. import Child from './Child.vue'
  22. import Child1 from './Child1.vue'
  23. import { ref } from 'vue'
  24. let info = ref('')
  25. //父组件的数据钱数
  26. let money = ref(10000)
  27. //自定义事件的回调
  28. const handler = num => {
  29. //将来接受子组件传递过来的数据
  30. money.value = num
  31. }
  32. //父亲的数据
  33. let pageNo = ref(1)
  34. let pageSize = ref(3)
  35. </script>
  36. <style scoped>
  37. </style>

5.useAttrs

useAttrs方法获取组件的属性与事件(包含:原生DOM事件或者自定义事件)

父组件AttrsListentersText

  1. <template>
  2. <div>
  3. <h1>useAttrs</h1>
  4. <el-button type="primary" size="small" :icon="Edit"></el-button>
  5. <!-- 自定义组件 -->
  6. <HintButton type="primary" size="small" :icon="Edit" title="编辑按钮" @click="handler" @xxx="handler"></HintButton>
  7. </div>
  8. </template>
  9. <script setup lang="ts">
  10. //vue3框架提供一个方法useAttrs方法,它可以获取组件身上的属性与事件!!!
  11. //图标组件
  12. import {
  13. Check,
  14. Delete,
  15. Edit,
  16. Message,
  17. Search,
  18. Star,
  19. } from "@element-plus/icons-vue";
  20. import HintButton from "./HintButton.vue";
  21. //按钮点击的回调
  22. const handler = () => {
  23. alert(12306);
  24. }
  25. </script>
  26. <style scoped></style>

hintButton.vue

  1. <template>
  2. <div :title="title">
  3. <el-button :="$attrs"></el-button>
  4. </div>
  5. </template>
  6. <script setup lang="ts">
  7. //引入useAttrs方法:获取组件标签身上属性与事件
  8. import { useAttrs } from 'vue';
  9. //此方法执行会返回一个对象
  10. let $attrs = useAttrs();
  11. let props = defineProps(['title']);
  12. //props与useAttrs方法都可以获取父组件传递过来的属性与属性值
  13. //props接受了useAttrs方法就获取不到了
  14. console.log($attrs);
  15. </script>
  16. <style scoped></style>

6.ref与$parent

ref可以获取元素的DOM或者获取子组件实例的VC

父组件内部代码: RefChildrenParentTest.vue

  1. <template>
  2. <div class="box">
  3. <h1>我是父亲曹操:{{ money }}</h1>
  4. <button @click="handler">找我的儿子曹植借10元</button>
  5. <hr>
  6. <Son ref="son"></Son>
  7. <hr>
  8. <Dau></Dau>
  9. </div>
  10. </template>
  11. <script setup lang="ts">
  12. //ref:可以获取真实的DOM节点,可以获取到子组件实例VC
  13. //$parent:可以在子组件内部获取到父组件的实例
  14. //引入子组件
  15. import Son from './Son.vue'
  16. import Dau from './Daughter.vue'
  17. import { ref } from 'vue';
  18. //父组件钱数
  19. let money = ref(100000000);
  20. //获取子组件的实例
  21. let son = ref();
  22. //父组件内部按钮点击回调
  23. const handler = () => {
  24. money.value += 10;
  25. //儿子钱数减去10
  26. son.value.money -= 10;
  27. son.value.fly();
  28. }
  29. //对外暴露
  30. defineExpose({
  31. money
  32. })
  33. </script>
  34. <style scoped>
  35. .box {
  36. width: 100vw;
  37. height: 500px;
  38. background: skyblue;
  39. }
  40. </style>

父组件获取子组件的数据或者方法需要通过defineExpose对外暴露,因为vue3中组件内部的数据对外“关闭的”,外部不能访问 

son.vue

  1. <template>
  2. <div class="son">
  3. <h3>我是子组件:曹植{{money}}</h3>
  4. </div>
  5. </template>
  6. <script setup lang="ts">
  7. import {ref} from 'vue';
  8. //儿子钱数
  9. let money = ref(666);
  10. const fly = ()=>{
  11. console.log('我可以飞');
  12. }
  13. //组件内部数据对外关闭的,别人不能访问
  14. //如果想让外部访问需要通过defineExpose方法对外暴露
  15. defineExpose({
  16. money,
  17. fly
  18. })
  19. </script>
  20. <style scoped>
  21. .son {
  22. width: 300px;
  23. height: 200px;
  24. background: cyan;
  25. }
  26. </style>

获取父组件的数据Daughter.vue

$parent可以获取某一个组件的父组件实例VC,因此可以使用父组件内部的数据与方法。必须子组件内部拥有一个按钮点击时候获取父组件实例,当然父组件的数据与方法需要通过defineExpose方法对外暴露

<button @click="handler($parent)">点击我获取父组件实例</button>
  1. <template>
  2. <div class="dau">
  3. <h3>我是曹操的闺女曹杰:{{ money }}</h3>
  4. <button @click="handlerFath($parent)">跟我老爸拿1000元</button>
  5. </div>
  6. </template>
  7. <script setup lang="ts">
  8. import { ref } from 'vue';
  9. //闺女钱数
  10. let money = ref(999999);
  11. //闺女按钮点击回调
  12. const handlerFath = (parent) => {
  13. money.value += 1000,
  14. console.log(parent.money -= 1000);
  15. // $parent.money -= 1000
  16. }
  17. </script>
  18. <style scoped>
  19. .dau {
  20. width: 300px;
  21. height: 300px;
  22. background: hotpink;
  23. }
  24. </style>

7.provide[提供]与inject[注入]

vue3提供两个方法provide与inject,可以实现隔辈组件传递参数

provide方法用于提供数据,此方法执需要传递两个参数,分别提供数据的key与提供数据value

  1. <script setup lang="ts">
  2. import {provide} from 'vue'
  3. provide('token','admin_token');
  4. </script>

 后代组件可以通过inject方法获取数据,通过key获取存储的数值

  1. <script setup lang="ts">
  2. import {inject} from 'vue'
  3. let token = inject('token');
  4. </script>
  5. // 可以进行修改
  6. const updateCar = ()=>{
  7. car.value = '自行车';
  8. }

 

 

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小小林熬夜学编程/article/detail/304657
推荐阅读