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:获取组件标签身上属性与事件
6.$ref/$parent
7.provide/inject
8.pinia :vuex:集中管理状态容器,可以实现任意组件之间的通信
9.slot 插槽分为默认插槽、具名插槽、作用域插槽(可以传递数据的插槽,子组件可以将数据回传给父组件的插槽)
父组件中,引入子组件并给子组件绑定一个money参数
父组件
富一代资产{{ money }}元
子组件中,使用defineProps接收,在template中,可以直接使用money,
子组件1
儿子不知道父亲有{{ porps.money }}元
儿子知道了会争这{{ money }}元(template中可以直接省略porps---script中无法省略!)
示例
说到$emit就要说一下自定义事件,在vue框架中事件分为两种:一种是原生的DOM事件,另外一种自定义事件。原生DOM事件可以让用户与网页进行交互,比如click、dbdlick、change、mouseenter、mouseleave...自定义事件可以实现子组件给父组件传递数据。vue2中的@click绑定的是自定义事件 ,可以通过.native修饰符变为原生DOM事件 。vue3中绑定的是原生事件,利用defineEmits方法返回函数触发自定义事件,不需要引入,直接使用。
父组件
父组件
富一代资产{{ money }}元
{{ son }}
子组件
子组件1
儿子不知道父亲有{{ porps.money }}元
儿子知道了会争这{{ money }}元(template中可以直接省略porps---script中无法省略!)
vue2中 @click是自定义事件,可以通过.native修饰符变为原生DOM事件。
在vue3中@click是原生DOM事件
自定义事件
示例:
mitt
Mitt
是一个小巧的JavaScript发布-订阅库,用于在应用程序中实现事件监听和触发。
安装:npm install mitt -S
在src目录下新建bus文件夹,bus文件夹下新建index.ts
// 引入mitt插件 index.ts
import mitt from "mitt"
const $bus = mitt();
export default $bus
接收组件:引入上面新建的bus,$bus.on 接收将来兄弟组件传递的数据
子组件1
收到{{ car }}
发送组件:$bus.emit 使用发送
子组件2
富二代的亲弟钱包有999999元
点击送富二代哥哥法拉利跑车一台
示例:
在vue2中v-model绑定了一个value值,和input事件,并且只能绑定一个v-model。
而在vue3中给子组件传递一个porps,并且绑定了一个自定义事件。
此处有两种用法,方法一
porps + @update:money 代表自定义事件。代码如下:
父组件代码:
父组件
父亲60大寿三妹送出价值{{ money3 }}元礼品
子组件
子组件3
父亲送给三妹 {{ modelValue }}元
点击送出
方法二
1.相当于给子组件传递一个porps[modelValue]=666666 (一定叫modelValue)
2.相当于给子组件绑定了一个自定义事件,事件名一定是 update:modelValue,父组件不用自己写自定义事件
父组件代码
父组件
父亲60大寿三妹送出价值{{ money3 }}元礼品
子组件:
注意:以v-model="money3"的形式传递时,使用defineProps 接收名字只能叫modelValue,默认写法。
传多个值时,父组件 以v-model:参数名="参数名" 形式传递,defineProps 接收名字就是参数名。
更改数据使用defineEmits,默认方式更改值 事件名字只能叫 “update:modelValue”,
更改指定名字的值时 事件名字 是 “update:参数名”
子组件3
父亲送给三妹 {{ modelValue }}元
名字:{{ name }}
年龄:{{ age }}
点击送出
点击更改名字和年龄
父组件
父组件
子组件:
在 使用
attrs
的情况应该是相对来说较为罕见的,因为可以在模板中直接通过 $attrs
来访问。在你的确需要使用它们的罕见场景中,可以 useAttrs
辅助函数。
porps和useAttrs都可以接收来自父组件传递过来的属性与属性值, 如果同时用porps接收值 ,那么useAttrs方法就无法再次获取,porps优先级高与useAttrs。 useAttr同时可以接收事件。
子组件4
useAttrs通信 :="$attrs"等价于 v-bind:{type:'primary' , size:'large' }
示例
ref:可以获取真实的DOM节点,可以获取子组件实例的VC
$parent:可以在子组件内部获取到父组件的实例
组件内部的数据对外是关闭的,不能直接访问。需要使用defineExpose对外暴露
父组件
父亲找5儿子借1元
父亲资产{{ money }}元
子组件
子组件5
ref:可以获取真实的DOM节点,可以获取子组件实例的VC
$parent:可以在子组件内部获取到父组件的实例
儿子剩余{{ money }}元
投资买楼资金不足,找爸爸要90000000(点击按钮注入$parent)
示例
1. vue3提供 provide (提供)与 inject (注入),事件隔辈组件数据传递。
2. 父组件提供数据(provide)需要两个参数:
第一个参数就是提供数据的key
第二个参数是提供的数据
3. 注入祖先组件提供的数据:提供的key
4. inject获取的数据是指向同一个对象,可以进行修改
父组件
子组件
子组件6
孙子组件
孙子组件
收到爷爷送的黄金{{ gold }}g
示例
Pinia | Pinia官网
核心概念 state mutations actions getters modules
pinia 核心概念 state actions getters
pinia分为两种写法,选择式api 写法=>类似与vuex 和组合式api写法
8.1.安装
yarn add pinia
# 或者使用 npm
npm install pinia
8.2.新建store文件夹,如下,分为两个模块讲解 选择式api写法 与 组合式api写法
8.3.index.ts
// 创建大仓库 index.ts
import { createPinia } from 'pinia'
// createPinia
let store =createPinia();
// 对外暴露
export default store
8.4.main.js : 引入 "./store"
import { createApp } from 'vue'
import App from "@/App.vue"
import "@/assets/style/common.scss"
import store from "./store"
const app = createApp(App)
app.use(store)
app.mount('#app')
8.5.user.ts 选择式api写法
// 定义user仓库 选择式api写法 user.ts
import { defineStore } from "pinia";
// defineStore传入两个参数 第一个是小仓库的名字,第二个是小仓库配置对象。
// defineStore方法执行会返回一个函数,函数作用就是让组件可以获取到仓库的数据
let userStore = defineStore("user", {
// 存储数据:state
state: () => {
return {
name: "梅赛德斯",
arr: [12, 234, 23434, 34534]
}
},
actions: {
// 注意函数没有context上下文对象,没有commit 没有mutation去修改数据
// 此处使用this就是小仓库对象--- 此处不能使用箭头函数
updateName(value: string) {
this.name = value
}
},
getters: {
totalMoney() {
let M: any = this.arr.reduce((prev: number, next: number) => {
return prev + next
}, 0)
return M
}
}
})
export default userStore
8.6.info.ts 组合式api写法
// 定义info仓库 组合式api写法 info.ts
import { defineStore } from "pinia";
import { ref, computed } from "vue"
let infoStore = defineStore("info", () => {
// 此处的箭头函数务必返回一个对象,属性与方法提供给组件使用
// 主要用到了vue3中的组合式API函数
let num = ref(34233)
const updateNum = (value: number) => {
num.value = value
}
// 使用计算属性
const newNum = computed(() => {
return num.value * 1000
})
return {
num,
newNum,
updateNum
}
})
export default infoStore
使用:
子组件7
名字:{{ userInfo.name }}
{{ userInfo.totalMoney }}
组合式api:{{ info.num }}
组合式api使用计算属性:{{ info.newNum }}
点击改名字
点击改num
示例
9.1 默认插槽 -父组件
父组件
1.我是默认插槽
子组件
子组件8
9.2 具名插槽 -父组件
父组件
我是具名插槽数据lora
我是具名插槽数据Marry
子组件
子组件8
-------
-------
9.3 作用域插槽 -父组件
父组件
{{ $row.type === 1 ? $row.name : $row.lable }}
index:{{ $index }}
子组件
子组件8
示例
以上是总结的所有通信方式