vue父子组件如何传递参数(VUE3+TS(父子、兄弟组件通信))
目录
父传子值 、方法(子调用父值 、方法)
子传父值(父调用子值)
父读子(子传父)(父调用子值 、方法)
兄弟(任意组件)通信
引入Mitt来完成任意组件通信
父传子值 、方法(子调用父值 、方法)
1 、统一规范写法 ,通过在子组件标签上绑定属性和值 ,来传递到子组件,子组件再通过defineProps来接收 ,先给其定义类型再用withDefaults是为了在不传递的时候给其一个默认值
//父组件直接在标签发送 <Children :aaa="aaa" :data="data"></Children> ------------------------------------------------ //子组件两种接收方式 //方式一:子组件定义类型再接收 //?表示可传可不传 type Props = { aaa?: String; data?: number[] }; //通过defineProps接受 ,给一个默认值 const a = withDefaults(defineProps<Props>(), { aaa: 张三, data: [1, 2], }); //调用 const changehandle = () => { console.log(a.aaa); console.log(a.data[0]); }; //方式二:子组件混合定义接收 import { PropType } from vue; const prop = defineProps({ aaa: { type: Object as PropType<Student>, default: () => { } }, //定义接收父组件方法 bbb: { type: Function, default: () => { } }, }) //调用 prop.aaa; prop.bbb();2 、利用vue自带的provide传递 、inject接受 ,用法很简单 ,需要响应式只需要用ref包起来
// 父组件 ,引入provide ,然后定义一个属性和值 import {provide} from vue provide(flag,xxx) // 子组件 ,先引入inject ,再获取 import {inject} from vue let data = inject(flag)子传父值(父调用子值)
先用defineEmits定义一个emit ,里面存放即将被调用的自定义事件名,然后将其写进一个方法里 ,再通过父组件来定义这个事件 ,触发事件即可获取绑定的属性值
//子组件定义一个点击事件 <el-button type="success" @click="changehandle">子组件按钮</el-button> //定义一个自定义事件 const emit = defineEmits([clickToFather]); //通过事件传过去 const changehandle = () => { emit(clickToFather, msg); }; //父组件使用自定义事件名 <Children @clickToFather="getList"></Children> //调用获取 const getList = (msg: string) => { console.log(msg); };父读子(子传父)(父调用子值 、方法)
简单来说就是父组件获取到子组件的实例,用实例来调用子组件的方法 ,但是和vue2不同的是 ,子组件需要将方法暴露出去,父组件才能通过实例获取到 ,这样就确保了足够的安全性
//子组件将值暴露出去 defineExpose({ msg, }); //父组件获得子组件的实例 <Children ref="menus"/> //定义 const menus = ref(null); //调用 const changehandle = () => { console.log(menus.value.msg); };兄弟(任意组件)通信
1、兄弟组件通信:可以先把值传给父组件 ,再通过父组件传给另一个子组件 ,就做到了兄弟组件的传参 ,但是问题就是及其麻烦 ,所以引出第二种方式
2 、通过消息的发布订阅来实现 ,定义一个bus(可实现任意组件通信)
先在父组件所在目录下定义一个Bus.ts文件
// 先定义一个类型 ,emit作为发布(传递) ,on作为订阅(接收) // name是事件名称 ,callback是一个回调函数 type BusClass = { emit:(name:string) => void on:(name:string, callback:Function) => void } // 定义多种参数类型 type PramsKey = string | number | symbol // 定义一个调用中心,可以接收多个参数 type List = { [key:PramsKey]: Array<Function> } class Bus implements BusClass { list: List constructor (){ // 初始化list this.list = {} } // 发布事件,...args解构多个参数 emit (name:string,...args:Array<any>){ // 获取到list里的数据 let evnentName:Array<Function> = this.list[name] evnentName.forEach(fn =>{ fn.apply(this, args) }) } // 接收事件 on (name:string, callback:Function){ // 如果是第一次注册,则为空;如果被多次注册 ,则采用之前注册的名字 let fn:Array<Function> = this.list[name] || [] fn.push(callback) this.list[name] = fn } } // 导出bus export default new Bus()现在来使用刚刚定义的bus ,将A组件的值传递给B组件
A组件
<button @click="emitB">派发一个事件</button> // 引入bus import Bus from ../Bus // 定义一个属性值 let flag = 我来自A组件 const emitB = () =>{ // 通过Bus发布出去一个on-click事件,并携带flag 参数 Bus.emit(on-click,flag) }B组件
// 引入bus import Bus from ../Bus // 接收事件 Bus.on(on-click,(flag: string) =>{ console.log(接收的值为,flag) })这样就完成了一个兄弟组件的传参
该方法不仅方便 ,且可以实现任意组件通信 ,极其方便实用!
该方法不仅方便,且可以实现任意组件通信 ,极其方便实用!
引入Mitt来完成任意组件通信
当然了 ,上面只是我们自己手写的Bus ,其实这个库别人早已写好了 ,我们可以直接引入
首先安装依赖:
#安装命令 npm install mitt -S全局使用
在main.ts文件中引入并开启使用
// 引入 import mitt from mitt //定义 const Mit = mitt() //全局声明 declare module vue { export interface ComponentCustomProperties{ $Bus: typeof Mit } } //使用 app.config.globalProperties.$Bus = Miit()引入完成 ,使用方式和手写的基本一致 ,只不过名字不同
A组件
<button @click="emit">派发一个事件</button> //引入 import {getCurentInstance} from vue //初始化 const instance = getCurentInstance() //使用(发送事件) const emit = () =>{ // emit(自定义事件名,参数,....) instance?.proxy?.$Bus.emit(on-click,xxx) }B组件
// 引入bus import getCurentInstance from vue // 初始化 const instance = getCurentInstance() // 接收事件 instance?.proxy?.$Bus.on(on-click,(xxx: string) =>{ console.log(接收的值为,xxx) })如果此时A组件发送了多个事件 ,B组件可以用*接收 ,写法如下
// yyy,xxx为两个事件的参数 instance?.proxy?.$Bus.on(*,(yyy,xxx) =>{ console.log(接收的值为,yyy,xxx) })有发送事件 ,自然还有取消事件
// 这里先把Bus提取出来 const Bus = (xxx) =>{ console.log(接收的值为,xxx) } // 这里依旧写on,接收事件 instance?.proxy?.$Bus.on(on-click,Bus) // 这里还可以调用取消指定事件 // off(取消指定的mitt事件,取消的函数) instance?.proxy?.$Bus.off(on-click,Bus) // 还可以取消全部事件 instance?.proxy?.$Bus.all.clear()该方法不仅方便 ,且可以实现任意组件通信 ,极其方便实用!
该方法不仅方便,且可以实现任意组件通信 ,极其方便实用!
创心域SEO版权声明:以上内容作者已申请原创保护,未经允许不得转载,侵权必究!授权事宜、对本内容有异议或投诉,敬请联系网站管理员,我们将尽快回复您,谢谢合作!