【vue3】学习笔记--组件通信方式

这篇具有很好参考价值的文章主要介绍了【vue3】学习笔记--组件通信方式。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

学习vue3总是绕不开vue2

vue2组件通信方式总结:

1、props:可以实现父子组件,子父组件,甚至兄弟组件通信
2、自定义事件:实现子父组件通信
3、全局事件总线$bus:可以实现任意组件通信
4、pubsub:发布订阅模式实现任意组件通信
5、vuex: 集中式状态管理容器,实现任意组件通信
6、ref:父组件获取子组件实例VC,获取子组件的响应式数据及方法
7、slot:插槽(默认插槽,具名插槽,作用域插槽),实现父子组件通信

vue3组件通信方式总结:

1、props
2、自定义事件
3、全局事件总线
4、v-model
5、useAttrs方法
6、ref与$parent
7、provide与inject
8、pinia组合式API
9、插槽

vue3组件通信方式如下:

1、父子组件通信props

props数据只读,从父组件传递到子组件,子组件内部不可直接更改
子组件需要使用defineProps方法接受父组件传递过来的数据
setup语法糖下局部组件无需注册直接可以使用
父组件

<template>
  <div class="box">
    <Child  :msg="msg" :count="count"></Child>
  </div>
</template>
<script setup lang="ts">
import Child from "./Child.vue";
import { ref } from "vue";
let msg= ref(10000);
let count= ref(1);
</script>

子组件

<template>
  <div class="son">  
       <p>{{msg}}</p>
  </div>
</template>
<script setup lang="ts">

let props = defineProps(['msg']); //数组可以
let props = defineProps({     //对象写法
msg:String,
count:Number
})
</script>
//编译器宏函数defineProps,编译器遇到defineProps标识,会在底层编译的时候将代码转变成之前的格式
const __sfc__ = {
__name:'child',
props:{
message:String,
count:Number
}
}

2、自定义事件传值

vue框架中事件分为两种:原生的DOM事件和自定义的事件,原始DOM事件可以让用户与网页进行交互,如:click,dbclick,mouseenter,mouseleave等
自定义事件可以实现子组件给父组件传递数据

如果在父组件的组件标签上直接使用原生DOM事件,在vue2中可以通过.native修饰符变为原生DOM事件,在vue3中就是原生事件,相当于给子组件的根节点绑定的事件,子组件中的任意内容都可以触发这个事件。

<Event1 @click="handler2"></Event1>

vue3中没有this,没有组件实例,利用defineEmits方法返回函数触发自定义事件
父组件

<template>
  <div>
   <!-- 绑定自定义事件xxx:实现子组件给父组件传递数据 -->
    <Event2 @xxx="handler3"  @click="handler4"></Event2>
  </div>
</template>
<script setup lang="ts">
//引入子组件
import Event2 from './Event2.vue';
const handler3 = (param1,param2)=>{
    console.log(param1,param2);
}
const handler4 = (param1,param2)=>{
     console.log(param1,param2);
}
</script>

子组件

<template>
  <div class="child">
    <p>我是子组件2</p>
    <button @click="handler">点击我触发自定义事件xxx</button>
    //直接在模板区触发,当在子组件中定义事件名为click,在父组件中即为自定义事件,不再是原生DOM事件
    <button @click="$emit('click','AK47','J20')">点击我触发自定义事件click</button>
  </div>
</template>

<script setup lang="ts">
//通过defineEmits编译器宏函数生成emit方法
let $emit = defineEmits(['xxx','click']);
//按钮点击回调
const handler = () => {
  //第一个参数:事件类型 第二个|三个|N参数即为注入数据
    $emit('xxx','东风导弹','航母');
};
</script>

3、兄弟组件传值

vue3框架中,没有vue构造函数,导致没有VM,也没有原型对象,以及组合式API写法setup没有this,可以用插件mitt实现全局事件总线功能。
mitt官网地址

npm install --save mitt

src目录下新建bus文件夹–index.ts文件中

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

emit触发事件,on接收参数

子组件1

import $bus from "../../bus";
import { onMounted } from "vue";
//组件挂载完毕的时候,当前组件绑定一个事件,接受将来兄弟组件传递的数据
onMounted(() => {
  //第一个参数:即为事件类型  第二个参数:即为事件回调
  $bus.on("car", (car) => {
    console.log(car);
  });
});

【vue3】学习笔记--组件通信方式,Vue3,学习,笔记,vue.js
子组件2

<template>
  <div class="child2">
     <button @click="handler">赠送车</button>
  </div>
</template>

<script setup lang="ts">
//引入$bus对象
import $bus from '../../bus';
//点击按钮回调
const handler = ()=>{
  $bus.emit('car',{car:"法拉利"});
}
</script>

4、v-model父子组件通信

vue2中不可以进行父子组件通信,vue3中相当于同时做了props和emit的工作
【vue3】学习笔记--组件通信方式,Vue3,学习,笔记,vue.js

5、useAttrs方法

useAttrs方法可以获取组件标签身上的属性与事件
如果同时使用props,props的优先级比useAttrs高。props接受了useAttrs方法就获取不到了
useAttrs方法不仅可以拿到组件标签身上的原生事件,自定义事件也可以拿到

父组件,父组件不需要向子组件传值,组件标签上的type,size,icon,原生事件及自定义事件都可以通过useAttrs方法获取到

<template>
  <div>
    <!-- 自定义组件 -->
    <HintButton type="primary" size="small" :icon="Edit" title="编辑按钮" @click="handler" @xxx="handler"></HintButton>
  </div>
</template>

子组件

<template>
  <div :title="title">
  //对象格式:{type:'primary',size:'small',icon:'Edit',title:'编辑按钮'}
     <el-button :="$attrs"></el-button>   
  </div>
</template>
//引入useAttrs方法:获取组件标签身上属性与事件
import {useAttrs} from 'vue';
//此方法执行会返回一个对象
let $attrs = useAttrs();

如果用props接收title

let props =defineProps(['title']);

props接受了useAttrs方法就获取不到了
【vue3】学习笔记--组件通信方式,Vue3,学习,笔记,vue.js
原生事件及自定义事件都可以通过useAttrs方法获取到
【vue3】学习笔记--组件通信方式,Vue3,学习,笔记,vue.js

6、ref与$parent

ref获取到真实的DOM节点,可以获取到子组件的实例VC
$parent可以在子组件的内部获取到父组件的实例

1、ref
在父组件通过ref获取子组件的实例

<template>
  <div class="box">
    <Son ref="son"></Son>
  </div>
</template>
import {ref} from 'vue';
let money = ref(100000000);
//获取子组件的实例,与组件标签上的ref同名,不然拿不到实例
let son = ref();

拿到子组件的实例后,组件内部数据对外是关闭的,别人不能访问,想让外部访问需要通过defineExpose方法对外暴露
子组件中

import {ref} from 'vue';
//子组件钱数
let money = ref(666);
defineExpose({
  money,

})

暴露之后,就可以在父组件改子组件的数据了
父组件

  <button @click="handler">修改</button>
  //父组件内部按钮点击回调
const handler = ()=>{
   //子组件钱数减去10
   son.value.money-=10;
 
}

2、$parent
在子组件内部,点击事件的参数中传入 $parent,(固定写法)

子组件

<template>
  <div class="dau">  
     <button @click="handler($parent)">点击我</button>
  </div>
</template>
import {ref} from 'vue';
//子组件钱数
let money = ref(999999);
//子组件按钮点击回调
const handler = ($parent)=>{
   money.value+=10000;
   $parent.money-=10000;
}

打印$parent
【vue3】学习笔记--组件通信方式,Vue3,学习,笔记,vue.js
没有拿到父组件的数据,需要在父组件也对外暴露一下
父组件

//对外暴露
defineExpose({
   money
})

此时再打印,就有数据了
【vue3】学习笔记--组件通信方式,Vue3,学习,笔记,vue.js

7、provide与inject

可以实现隔辈组件的通信,provide(提供),inject(注入)
1、祖先组件:祖先组件给后代组件提供数据

import { ref, provide } from "vue";
let car = ref("法拉利");

provide 方法有两个参数,key以及value

//两个参数:第一个参数就是提供的数据key
//第二个参数:祖先组件提供数据
provide("getData", car);

2、后辈组件,子组件/孙子组件都可以使用并且可以修改值

 <button @click="updateCar">更新数据</button>
import {inject} from 'vue';
//注入祖先组件提供数据
//需要参数:即为祖先提供数据的key
let car = inject('getData');
const updateCar = ()=>{
   car.value  = '自行车';
}

8、pinia选择式API

vue3中pinia是个大菠萝,看着这么可爱的卡通形象,似乎学习pinia的知识也不是那么枯燥了。
Pinia中文文档
【vue3】学习笔记--组件通信方式,Vue3,学习,笔记,vue.js
pinia类似于vue2中的vuex
vuex:集中式管理状态容器,可以实现任意组件之间的通信
核心概念:state、mutations、actions、getters、modules
pinia:集中式管理状态容器,可以实现任意组件之间的通信
核心概念:state、actions、getters

1、src目录下新建store文件夹,新建index.ts及modules文件下,目录如下:
【vue3】学习笔记--组件通信方式,Vue3,学习,笔记,vue.js
index.ts

//创建大仓库
import { createPinia } from 'pinia';
//createPinia方法可以用于创建大仓库
let store = createPinia();
//对外暴露,安装仓库
export default store;

在main.ts中引入并使用

//引入仓库
import store from './store'
app.use(store)

引入成功后,可以看到
【vue3】学习笔记--组件通信方式,Vue3,学习,笔记,vue.js
pinia写法:选择式API和组合式API
1、选择式API在modules中定义小的仓库,info

//defineStore 用于定义小仓库,从pinia中获取
//定义info小仓库
import { defineStore } from "pinia";
//defineStore需要传递两个参数,第一个参数:小仓库名字  第二个参数:小仓库配置对象
//defineStore方法执行会返回一个函数,函数作用就是让组件可以获取到仓库数据
let useInfoStore = defineStore("info", {
    //存储数据:state,vuex中state是对象写法,pinia中是函数写法,函数返回的对象才是给组件提供的数据
    state: () => {
        return {
            count: 99,
            arr: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
        }
    },
    actions: {
    //vuex中commit提交,mutation去修改,pinia中没有mutation,直接在action中修改
        //注意:函数没有context上下文对象,pinia中使用this获取state中的数据
        //没有commit、没有mutations去修改数据
        updateNum(a: number, b: number) {
            this.count += a;
        }
    },
    
    getters: {
        total() {
            let result:any = this.arr.reduce((prev: number, next: number) => {
                return prev + next;
            }, 0);
            return result;
        }
    }
});
//对外暴露方法
export default useInfoStore;

在组件中使用,当数据改变的时候,所有使用的组件中的数据都会一同改变

import useInfoStore from "../../store/modules/info";
//获取小仓库对象
let infoStore = useInfoStore();
console.log(infoStore);

【vue3】学习笔记--组件通信方式,Vue3,学习,笔记,vue.js
修改数据

  <button @click="updateCount">点击我修改仓库数据</button>
  

```bash
//修改数据方法
const updateCount = () => {
//可以直接这么写:
//infoStore.count++
//用$patch方法用一个新的对象替换原来的对象
infoStore.$dispath({
count:1111
})

  //仓库调用自身的方法去修改仓库的数据,在info.ts的actions中定义这个方法
  infoStore.updateNum(66,77);
};

【vue3】学习笔记--组件通信方式,Vue3,学习,笔记,vue.js
2、组合式API,在modules中定义小的仓库,todo

//定义组合式API仓库
import { defineStore } from "pinia";
import { ref, computed,watch} from 'vue';
//创建小仓库
let useTodoStore = defineStore('todo', () => {
    let todos = ref([{ id: 1, title: '吃饭' }, { id: 2, title: '睡觉' }, { id: 3, title: '打豆豆' }]);
    let arr = ref([1,2,3,4,5]);

    const total = computed(() => {
        return arr.value.reduce((prev, next) => {
            return prev + next;
        }, 0)
    })
    //务必要返回一个对象:属性与方法可以提供给组件使用
    return {
        todos,
        arr,
        total,
        updateTodo() {
            todos.value.push({ id: 4, title: '组合式API方法' });
        }
    }
});

export default useTodoStore;

在组件中使用

  <p @click="updateTodo">{{ todoStore.arr }}{{todoStore.total}}</p>
import useInfoStore from "../../store/modules/info";
//获取小仓库对象
let infoStore = useInfoStore();

//引入组合式API函数仓库
import useTodoStore from "../../store/modules/todo";
let todoStore = useTodoStore();

//点击p段落去修改仓库的数据
const updateTodo = () => {
  todoStore.updateTodo();
};

9、插槽

插槽有三种:默认插槽,具名插槽,作用域插槽

默认插槽,在子组件中放置slot,在父组件的子组件标签中添加的任意内容都会显示在插槽位置

1、默认插槽
子组件:

<template>
  <div class="box">
    <h1>我是子组件默认插槽</h1>
    <!-- 默认插槽 -->
    <slot></slot> 
  </div>
</template>

父组件

<template>
  <div class="box">
<Test>
      <div>
        <pre>大江东去浪淘尽,千古分流人物</pre>
      </div>
    </Test>
      </div>
</template>

【vue3】学习笔记--组件通信方式,Vue3,学习,笔记,vue.js
2、具名插槽
具名插槽就是有名字的插槽,子组件将坑位留好,父组件根据插槽名对应的添置内容
v-slot 写法等同于#,v-slot=a相当于#a

子组件

<template>
  <div class="box">
    <h1>具名插槽填充数据a</h1>
    <slot name="a"></slot>
    <h1>具名插槽填充数据b</h1>
    <slot name="b"></slot>
    <h1>具名插槽填充数据</h1>
  </div>
</template>

父组件

<template>
  <div>
    <h1>slot</h1>
    <Test1 :todos="todos">
      <template v-slot="{ $row, $index }">
        <p :style="{ color: $row.done ? 'green' : 'red' }">
          {{ $row.title }}--{{ $index }}
        </p>
      </template>
    </Test1>
    <Test>    
      <!-- 具名插槽填充a -->
      <template #a>
        <div>我是填充具名插槽a位置结构</div>
      </template>
      <!-- 具名插槽填充b v-slot指令可以简化为# -->
      <template #b>
        <div>我是填充具名插槽b位置结构</div>
      </template>
    </Test>
  </div>
</template>

【vue3】学习笔记--组件通信方式,Vue3,学习,笔记,vue.js
3、作用域插槽
作用域插槽我多花了点时间去理解,似乎和之前vue2的理解有点不一样,也有可能是在使用vue2的时候没有特别关注作用域插槽的实现。

作用域插槽是可以传递数据的插槽,子组件可以将数据回传给父组件。父组件可以决定这些回传的数据以何种结构或外观在子组件内部去展示。

举个例子,当我们封装了一个列表组件并配有一些查询的输入框或下拉框,a调用页面需要:使用者姓名,使用者部门这两个查询条件,b调用页面需要:商品名称,商品编号这两个查询条件,而除了查询条件不同,其他的都一样,我们不可能封装很多个子组件,那就没有复用的意义了。这个时候就可以使用作用域插槽,在父页面的时候将数据传给子组件,子组件通过作用域插槽将数据回传给父组件,父组件的子组件标签内部通过template标签展示,从而实现展示不同的查询条件。

父组件给子组件传递todos数组

    <Test1 :todos="todos">
    </Test1>
import { ref } from "vue";
//todos数据
let todos = ref([
  { id: 1, title: "吃饭", done: true },
  { id: 2, title: "睡觉", done: false },
  { id: 3, title: "打豆豆", done: true },
  { id: 4, title: "打游戏", done: false },
]);

子组件接收并在内部使用

<template>
  <div class="box">
    <ul>
      <li v-for="(item, index) in todos" :key="item.id">     
      </li>
    </ul>
  </div>
</template>
defineProps(["todos"]);

当我们开始在子组件内部使用作用域插槽,对象中是key和value对应,$row 和 $index相当于是我们定义的key,后面跟的是对应的value。

<template>
  <div class="box">
    <ul>
      <li v-for="(item, index) in todos" :key="item.id">
        <slot :$row="item" :$index="index"></slot>
      </li>
    </ul>
  </div>
</template>

在父组件的子组件标签内部使用插槽回传的数据

<Test1 :todos="todos">
      <template v-slot="{ $row, $index }">
        <p :style="{ color: $row.done ? 'green' : 'red' }">
          {{ $row.title }}--{{ $index }}
        </p>
      </template>
    </Test1>

可能会有疑惑,为啥要写的这么复杂,要从父组件传进去,再传出来。如果a调用页面需要的是绿色和红色两种颜色的判断,而b调用页面需要的是紫色和蓝色的判断,甚至是c,d等调用页面需要其他的颜色。甚至是包裹的标签这个需要p标签,那个需要div标签,甚至是其他的外观或者结构需要不同的展示

也许我们习惯的是从父组件传一个变量到子组件,在子组件内部通过v-if,v-else-if来判断不同的条件。不是很复杂的用哪种都可以,复杂的可以考虑作用域插槽,多一种实现方式,也不是非用不可。文章来源地址https://www.toymoban.com/news/detail-537267.html

到了这里,关于【vue3】学习笔记--组件通信方式的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【Vue3】学习笔记-新的组件

    在Vue2中: 组件必须有一个根标签 在Vue3中: 组件可以没有根标签, 内部会将多个标签包含在一个Fragment虚拟元素中 好处: 减少标签层级, 减小内存占用 什么是Teleport?—— Teleport 是一种能够将我们的 组件html结构 移动到指定位置的技术。 等待异步组件时渲染一些额外内容,让应

    2024年02月16日
    浏览(40)
  • 前端学习笔记(14)-Vue3组件传参

    1.props(父组件传递给子组件) 1.1 实现 如果你没有使用 script setup,props 必须以 props 选项的方式声明,props 对象会作为 setup() 函数的第一个参数被传入: 在子组件中: 在父组件中: 一个组件可以有任意多的 props,默认情况下,所有 prop 都接受任意类型的值。 这种情况下,我

    2024年01月21日
    浏览(51)
  • VUE3 组件通信

    用途:可以实现父子组件、子父组件、甚至兄弟组件通信 父组件 子组件 用途:可以实现子父组件通信 父组件 子组件 用途:可以实现任意组件通信 安装  配置 新建bus.js文件 使用 父组件 子组件 父组件 子组件 父组件 子组件 父组件 子组件 父组件 儿子组件1 儿子组件2 安装

    2024年03月19日
    浏览(43)
  • vue3组件通信详解

    vue3组件通信方式有以下几种:porps,$emit, bus,v-model, useAttrs ,$ref/$parent,provide/inject,pinia,slot。下面将逐一讲解。    目录 1.porps:实现父子组件通信,子组件接收的数据还是只读  2.$emit 3.全局事件总线 $bus,使用mitt 4.v-model传值 5. $attrs/useAttrs:获取组件标签身上属性与

    2024年02月07日
    浏览(36)
  • vue3.0组件通信

    没有加TS限制类型的时候 注意: defineProps()会返回一个对象,这个对象可以直接.出数据 加TS写法 规则: 非函数类型 基本数据类型 - 展示 引用数据类型 - 展示,但是可以修改属性,不推荐(违反单向数据流 - 不是绝对禁止使用的,偷懒可以用) 函数类型 - 子组件调用父组件传过来的函数

    2024年02月12日
    浏览(40)
  • vue3-父子组件间通信

    在实际业务开发的过程中,我们时常会遇到组件间的通信问题,比如:父子组件间通信、同级组件间通信等。本篇文章中主要介绍父子组件间通信。父子组件间通信主要有以下常见形式: 方案 父组件向子组件 子组件向父组件 props/emits props emits v-model/emits v-model emits ref/emits

    2024年02月05日
    浏览(61)
  • Vue3 组件之间的通信

    经过前面几章的阅读,相信开发者已经可以搭建一个基础的 Vue 3 项目了! 但实际业务开发过程中,还会遇到一些组件之间的通信问题,父子组件通信、兄弟组件通信、爷孙组件通信,还有一些全局通信的场景。 这一章就按使用场景来划分对应的章节吧,在什么场景下遇到问

    2023年04月08日
    浏览(43)
  • Vue3组件通信相关内容整理

    适用于:  父向子传递参数、方法, 子触发父传递的方法 props方式组件通信和vue2中的props传参类似,只是使用方式和接收方式有一些区别。 注意点: 通过props方式传递的参数为 只读属性,不可修改 父组件 子组件  组件A :绑定事件-接收数据  组件B:触发事件-传递数据 这

    2024年01月25日
    浏览(40)
  • vue3组件通信之pinia

      在vue3,vue的状态管理也迎来了新的变更,在vue3使用新的组件pinia来代理原有的vuex。pinia相比vuex,功能收敛了不少,比如不直接暴露setter方式,外部直接修改数据 vuex:集中式管理状态容器,可以实现任意组件之间通信 核心概念:state、mutations、actions、getters、modules pinia:集中式

    2024年02月11日
    浏览(39)
  • vue3 快速入门系列 —— 组件通信

    组件通信在开发中非常重要,通信就是你给我一点东西,我给你一点东西。 本篇将分析 vue3 中组件间的通信方式。 Tip :下文提到的绝大多数通信方式在 vue2 中都有,但是在写法上有一些差异。 在 vue3 基础上进行。 新建三个组件:爷爷、父亲、孩子A、孩子B,在主页 Home.vu

    2024年04月17日
    浏览(61)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包