前言:
vue组件间通信对于经常来写vue的伙伴来说应该是很轻松的,对于一些刚入门的伙伴来说可能就有些迷茫,感觉方式有很多种,但是总结起来又不知道应该怎么说,在下面的文章中,我结合自己的开发过程中经常用到的一些组件传参方式做一个总结,也相当于是给自己做一个总结,毕竟在vue中,组件间的通信也是非常重要的一个环节。在写作过程中如果有什么不对的地方,希望看到的大佬能帮忙指出,如果本文能帮助到你,不胜荣幸。
相关通信方式
- props 和 emits传参
- 路由传参(query、params)
- 第三方库(pubsub-js)
- 依赖注入(provide,inject)
…
1、props 和 emits 传参 (父子组件传参)
使用props传参应该是vue里面用的最多的,因为是vue自带的传参方式,通过prop和emit传递参数,书写代码很简单,使用起来也是很方便的。但是通常我们是用来作为父子间组件传参,如果是兄弟组件传参就没有那么方便了(当然也不是不可以,只是会麻烦一点)
两种方式使用props和emits
1.1 不使用组合式API的写法
- 🚉 这里是父组件,名字App
<template>
<div>
<Test @sendData="getData" :name="张三" :age="18" :isMan="true" />
</div>
</template>
<script>
import Test from "@/components/Test.vue";
export default defineComponent({
name: "App",
components: {
Test
},
setup(){
const getData = (e) => {
console.log(e) //输出从子组件哪里得到的数据
};
return {getData}
}
)}
</script>
- 🚗 这里是子组件,定义名字为Test
<template>
<button @click="test()">传参给父组件</button>
</template>
<script>
import { defineComponent} from "vue";
export default defineComponent({
name: "Test",
components: {},
props: {
name: {
type: String,
default: '',
},
isMan: {
type: Boolean,
default: true,
},
age:{
type:Number,
default:0
}
},
emits: ['sendData'],
setup(props,{emit}) {
console.log(props) //输出父组件通过传过来的参数
const test = () => {
emit("sendData", '参数送过来了,父组件,查收一下');//第一个是在父组件中定义的方法,第二个是传递参数
};
return {
test
};
},
});
</script>
1.2 使用组合式API
方法和上面都差不多,主要的区别在于 < script>标签的写法,请仔细看我们下面的代码,看不同之处,是不是看起来简洁了很多呢
- 🚉 这里是父组件,名字App
<template>
<div>
<Test @sendData="getData" :name="张三" :age="18" :isMan="true" />
</div>
</template>
<script setup> //这里就直接在script标签上写上setup,就可以使用语法糖了,简洁高效
import Test from "@/components/Test.vue";
const getData = (e) => {
console.log(e) //输出从子组件哪里得到的数据
};
</script>
- 🚗 这里是子组件,定义名字为Test
<template>
<button @click="test()">传参给父组件</button>
</template>
<script setup>
import { defineProps,defineEmits } from "vue";
const props = defineProps({
name: {
type: String,
default: '',
},
isMan: {
type: Boolean,
default: true,
},
age:{
type:Number,
default:0
}
)}
const emits = defineEmits(['sendData'])
console.log(props) //输出父组件通过传过来的参数
const test = () => {
emits("sendData", '参数送过来了,父组件,查收一下');//第一个是在父组件中定义的方法,第二个是传递参数
};
</script>
是不是觉得第二种用语法糖的方式简单很多呢
2、路由传参【query、params】(仅限于路由跳转使用)
传参方式直接可观,通过路由传参,可以很便捷的将参数传给下一级路由。
通常使用query传递基本类型的数据(如:字符串,整型等)
params传递引用类型的参数(如:对象、数组等)
query传递的参数可以直接在我们的URL地址栏中可以看到(基本上在地址栏的问号(?)后面)
params传递的参数需要在控制台中去看,也可以利用浏览器中的vue插件进行查看
下面给大家两个代码示例看一下应该就很好理解了(这里使用的是vue2的写法,vue3路由的写法需要使用两个函数【useRoute, useRouter】使用方式相较于vue2的写法有一点点差距,如果写过react的朋友就很清楚了,这两个钩子和react的hooks是类似的。先给大家简单演示一下vue3怎么进行路由传参吧)
vue3路由写法
- 当前路由传参
import { useRoute, useRouter } from "vue-router"; //导入两个方法
const route = useRoute();
const router = useRouter();
const goTest = () => {
router.push({
path:"/admin/test",//路由组件路径
query:'测试数据传递'
});
};
- 下级路由接收参数
<script setup>
import {useRoute} from 'vue-router'
const route = useRoute();
console.log(route.query)
</script>
关于vue3 params传参可以看看下面的params,一个写法。这里就不做多赘述了。但要提醒以下两点:
- vue3使用params传参的时候版本过高有的时候会提示params参数丢失。可以参考修改一下vue-router的版本
- 在vue3中params传递参数被认为是不可靠的,因为在刷新页面的时候,params传递的参数会消失,如果我们使用了params传参,可能会导致页面数据丢失,因此vue3中,我们就尽量不要使用params传递参数了,同时也被认为是路由中的一种反模式,具体的详细信息可以参考:
https://github.com/vuejs/router/blob/main/packages/router/CHANGELOG.md#414-2022-08-22
2.1 query
- 当前本级路由的代码,使用query来传递一个id
this.$router.push({
//Test表示我们进入下一级路由的名字,这个name也可以换成path,但是相对应的参数也需要修改,主要看得是我们在vue路由中怎么定义的
path: '/admin/path', query: {
id:123
}
});
- 下一级接收参数 路由代码
created () { //生命周期函数
console.log(this..$route.query.ID) //输出我们这一级通过路由query得到的ID
}
2.2 params
和query类似,换汤不换药
- 当前本级路由的代码,使用params来传递多个参数
this.$router.push({
name: 'Test', params: {
person:{ID:'93808',age:12,name:'张三'}
}
});
- 下一级接收参数 路由代码
created () { //生命周期函数
console.log(this..$route.params.person.ID) //输出我们这一级通过路由params得到的ID
console.log(this..$route.params.person.age)
console.log(this..$route.params.person.name)
}
- 注
- vue2路由传参使用params传参,路径push的参数需要使用name(name就是组件定义的名称),query使用path(组件定义的路径)
3、pubsub-js(兄弟组件传参)
这是一个第三方库,需要安装
npm install pbusub-js
个人主要是用在兄弟传参上的,因为在兄弟传参上,再使用props或者emits就太麻烦了,因为这个确实比较简单我就不多说了,直接看下代码。
然后记一下它两个比较重要的方法
publish() : 消息发布
subscribe():消息订阅
- 🚓兄弟组件Test.vue
<template>
<div>
<h1>Test组件</h1>
<button @click="sendData"></button>
</div>
</template>
<script setup>
import PubSub from "pubsub-js";
const sendData = ()=>{
PubSub.publish('test', '发送数据给Test1')
}
</script>
- 🚕 兄弟组件Test1.vue
<template>
<div>
<h1>Test1组件</h1>
</div>
</template>
<script setup>
import PubSub from "pubsub-js";
PubSub.subscribe('test', (_, value) => {
console.log(value)
})
</script>
4、依赖注入(深层次组件传参)
vue自带的一种组件传参方式,不同于props和emits传参,它的传参可以直接通过一级组件传给三级组件而不用通过二级组件进行中转。画个图浅析一下。
通过上图,可以看出来深层次组件传参时,不用使用props来作为中转站,而且这里只是做了一个三级组件,有可能还有四级五级,如果使用props作为中转就太麻烦了。其用法也很简单,和pubsubJS用法有一些相似。
再上个例子,使用vue3组合式API写法
- 🚓一级组件Test.vue
<script setup>
import { provide, ref } from 'vue';
import Test1 from './components/Test1.vue';
let count = ref(0);
provide("message", count)
const countAdd = () => {
count.value++
}
</script>
<template>
<div class="app_layout">
<a-button @click="countAdd">增加</a-button>
<Test1 />
</div>
</template>
<style scoped></style>
</script>
- 🚕 三级组件Test2.vue
<script setup>
import { inject } from 'vue';
const message = inject("message")
</script>
<template>
<div>
<h1>三级组件</h1>
<h3>{{ message }}</h3>
</div>
</template>
<style lang='less' scoped></style>
最后在补充一下,inject可以接收第二个参数作为默认参数进行展示,当上级组件没有对该组件进行传参时,就会使用这个默认的参数进行展示,如上面三级组件中的参数接收方式可以修改成下面的方式:
<script setup>
import { inject } from 'vue';
const message = inject("message","当一级组件不传参,我是默认展示的参数")
</script>
<template>
<div>
<h1>三级组件</h1>
<h3>{{ message }}</h3>
</div>
</template>
另外也可以使用传入一个函数进行使用,具体方式这里没写,需要了解的可以参考官方文档,也是比较简单的。
https://cn.vuejs.org/api/composition-api-dependency-injection.html
总结
最后也简单总结一下,在使用vue中,使用这四种方式基本可以覆盖完我们写vue时面临的组件间传参遇到的问题了,其中
路由传参仅限于路由跳转之间参数的传递方式
props和emits用于父子组件间传参
provide和inject用于深层次组件传参很方便
pubsub-js属于第三方库,用于兄弟组件传参比较方便。
至于具体使用那种,主要看自己项目以及个人习惯
本次分享就到这里