前言
数据传递是框架的核心要素之一,也是在业务开发中极其重要的技术.熟练掌握所有的通信方法,是开发者必须具备的技能。
这篇文章我将会把vue2所有的通信的方法都形成简单易懂的demo。
在我的分类中,通信方法有两种大类型:
1.vue框架提供的通信方法
2.插件及其他通信方法
一.vue框架提供的通信方法:
1.props通信
props通信方法可以实现父组件向子组件传递参数,也可以实现子组件给父组件传递参数.
父传子:传递常规变量
子传父:传递函数
父组件
<template>
<div>
<p>父组件数字值1:{{ numValue1 }} <el-button @click="addNum">增加</el-button></p>
<p>获取子组件的值:{{ numValue2 }}</el-button></p>
<hr />
<PropsChild :numValue1="numValue1" :numValue2="getChildValue"></PropsChild>
</div>
</template>
<script>
import PropsChild from './child.vue'
export default {
name: 'propsTest',
components: {
PropsChild
},
data() {
return {
numValue1: 0,
numValue2: '父组件默认的值'
}
},
methods: {
addNum() {
this.numValue1++
},
getChildValue(childValue) {
console.log(childValue, '???子组件的数值')
this.numValue2 = childValue
},
getChildValueFun() {
}
}
}
</script>
<style lang="less"></style>
子组件
<template>
<div>
子组件
<el-input v-model="value" @input="changeValue"></el-input>
</div>
</template>
<script>
export default{
name:'emitChild',
data(){
return{
value:'子组件默认的值'
}
},
methods:{
changeValue(){
this.$emit('getChildValue',this.value)
}
}
}
</script>
<style lang="less">
</style>
效果:
2.emit通信(自定义事件)
父组件
<template>
<div>
父组件
<el-input v-model="value"></el-input>
<hr>
<EmitChild @getChildValue="getChildValue"></EmitChild>
</div>
</template>
<script>
import EmitChild from './child.vue'
export default{
name:'emitTest',
data(){
return{
value:'父组件默认的值'
}
},
components:{
EmitChild
},
methods:{
getChildValue(childValue){
this.value = childValue
}
}
}
</script>
<style lang="less">
</style>
子组件
<template>
<div>
子组件
<el-input v-model="value" @input="changeValue"></el-input>
</div>
</template>
<script>
export default{
name:'emitChild',
data(){
return{
value:'子组件默认的值'
}
},
methods:{
changeValue(){
this.$emit('getChildValue',this.value)
}
}
}
</script>
<style lang="less">
</style>
效果
3.evenBus(全局事件总线)
main.js安装事件总线
new Vue({
router,
store,
axios,
//配置事件总线
beforeCreate(){
Vue.prototype.$bus = this
},
render: h => h(App),
}).$mount('#app')
任意组件1:
<template>
<div>
<p>子组件1</p>
<p>子组件1的值:{{ value1 }} <el-button @click="addNum">增加</el-button></p>
<p>来自子组件2的值:{{ value2 }}</p>
</div>
</template>
<script>
export default{
name:'child1',
data(){
return{
value1:0,
value2:100
}
},
created(){
this.$eventBus.$on('bus_deleteNum',this.changeValue2)
},
methods:{
addNum(){
this.value1++
this.$eventBus.$emit('bus_addNum',this.value1)
},
changeValue2(val){
this.value2 = val
}
},
destroyed(){
this.$eventBus.$off('bus_deleteNum')
}
}
</script>
任意组件2
<template>
<div>
子组件2
<p>来自子组件1的值:{{ value1 }}</p>
<p>子组件2的值:{{ value2 }} <el-button @click="deleteNum">减少</el-button> </p>
</div>
</template>
<script>
export default{
name:'child2',
data(){
return{
value1:0,
value2:100
}
},
created(){
this.$eventBus.$on('bus_addNum',this.changeValue1)
},
methods:{
changeValue1(value){
this.value1 = value
},
deleteNum(){
this.value2--
this.$eventBus.$emit('bus_deleteNum',this.value2)
}
},
destroyed(){
this.$eventBus.$off('bus_addNum')
}
}
</script>
效果
4.ref通信
父组件
<template>
<div>
<p>父组件的值:{{ value }} <el-button @click="addNum">增加</el-button> </p>
<hr>
<Child ref="child"></Child>
</div>
</template>
<script>
import Child from './child.vue'
export default{
name:'refTest',
components:{
Child
},
data(){
return{
value:0
}
},
methods:{
addNum(){
this.value++
this.$refs.child.getValue(this.value)
}
}
}
</script>
子组件
<template>
<div>
子组件的值{{ value }}
</div>
</template>
<script>
export default{
name:'refTest',
data(){
return{
value:'子组件初始化的值'
}
},
methods:{
getValue(val){
this.value = val
}
}
}
</script>
效果
5.组件v-model通信
v-model不仅可以在输入类型标签上实现双向数据绑定,也可以在组件上实现父子组件数据通信
父组件
<template>
<div>
<el-input v-model="value"></el-input>
<hr />
<Child v-model="value" @changeValue="changeValue"></Child>
</div>
</template>
<script>
import Child from "./child.vue";
export default {
name: "vModel",
components: {
Child,
},
data() {
return {
value: "父组件默认的值",
};
},
methods: {
changeValue(data) {
this.value = data;
},
},
};
</script>
子组件
<template>
<div>
子组件
<el-input v-model="inputvalue" @input="changeValue"></el-input>
</div>
</template>
<script>
export default {
name: "child",
props: ["value"],
model: {
prop: "value",
event: "changeValue",
},
data() {
return {
inputvalue: "子组件默认的值",
};
},
create() {
//子组件初始化同步,注释掉则为默认值
// this.inputvalue = this.value;
},
methods: {
changeValue(val) {
this.$emit("changeValue", val);
},
},
watch: {
value: function (newVal) {
this.inputvalue = newVal;
},
},
};
</script>
效果
父子组件数据同步
6.sync修饰符通信
sync修饰符也是一种语法糖,也可以实现父子通信
父组件
<template>
<div>
<div>sync模块</div>
<el-input v-model="value"></el-input>
<hr />
<Child :value.sync="value" @changeVal="changeVal"></Child>
</div>
</template>
<script>
import Child from "./child.vue";
export default {
name: "sync",
components: {
Child,
},
data() {
return {
value: "父组件默认的值",
};
},
methods: {
changeVal(val) {
this.value = val;
},
},
};
</script>
<style lang="less" scoped>
</style>
子组件
<template>
<div>
<p>子组件</p>
<el-input v-model="childValue" @input="changeVal"></el-input>
</div>
</template>
<script>
export default {
name: "child",
props: ["value"],
data() {
return {
childValue: "子组件默认的值",
};
},
methods: {
changeVal() {
this.$emit("changeVal", this.childValue);
},
},
watch: {
value: function (newVal) {
this.childValue = newVal;
},
},
};
</script>
<style lang="less" scoped>
</style>
效果
7.$attr 和 $listeners
父组件
<template>
<div>
<p>$attrs与$listeners</p>
<p>title的值:<el-input class="inputBox" v-model="title"></el-input></p>
<p>数值1:<el-input class="inputBox" v-model="value1"></el-input></p>
<p>数值2:<el-input class="inputBox" v-model="value2.value"></el-input></p>
<p>数字值:{{ num }}</p>
<hr />
<Child
:title="title"
:value1="value1"
:value2="value2"
v-on="$listeners"
@changeNum="changeNum"
></Child>
</div>
</template>
<script>
import Child from "./child.vue";
export default {
name: "AttrListen",
components: {
Child,
},
data() {
return {
title: "标题",
value1: "数值1",
value2: {
value: "对象字段2",
},
num: 0,
};
},
mounted() {},
methods: {
changeNum() {
this.num++;
},
},
};
</script>
<style lang="less" scoped>
.inputBox {
width: 300px;
}
</style>
子组件
<template>
<div>
<p>子组件</p>
<p>title的值:{{ $attrs.title }}</p>
<p>数值1:{{ $attrs.value1 }}</p>
<p>数值2:{{ $attrs.value2.value }}</p>
<el-button @click="changeNum">修改值</el-button>
</div>
</template>
<script>
export default {
name: "child",
created() {},
methods: {
changeNum() {
console.log(this.$listeners, "this.$listeners的值子组件");
// this.$emit("changeNum");
this.$listeners.changeNum();
},
},
};
</script>
<style lang="less" scoped>
</style>
效果
8. provide和inject
可以实现上层组件对于后代组件的值传递,相当于穿透传递
祖先组件(这里使用app.vue)
<template>
<div id="app">
<router-view></router-view> </div>
</template>
<script>
export default {
name: 'App',
provide(){
return{
penetrateVal:'穿透的值'
}
},
components: {
},
created(){
},
methods:{
}
}
</script>
任意后代组件
<template>
<div>
<p>穿透值:{{ penetrateVal }}</p>
</div>
</template>
<script>
export default {
name: 'prodvideAndInject',
inject: ['penetrateVal'],
methods: {
}
}
</script>
<style></style>
效果
9.作用域插槽
父组件
<template>
<div>
父组件
<hr>
<Child>
<template slot-scope="num">
<span>父组件中使用:{{ num.data }}</span>
</template>
</Child>
</div>
</template>
<script>
import Child from './child.vue'
export default {
name: 'slotVal',
components: {
Child
},
}
</script>
子组件
<template>
<div>
<slot :data="num"></slot>
<el-button @click="add">子组件中点击增加</el-button>
</div>
</template>
<script>
export default{
name:'Child',
data(){
return{
num:0
}
},
methods:{
add(){
this.num ++
}
}
}
</script>
效果
以上都是vue框架自带的通信方法,但是在开发业务中是不够用的,因为还需要有一些全局的通信方法,去实现业务逻辑。
二.插件和其他的通信方法
这里的一些方法就不写具体的demo和效果图了,只是做一个简单的介绍
1.vue-router
路由传参是实现参数传递的重要途径,想必是个vue开发者肯定都用过吧
传递方
this.$router.push({path:'/demo1',query:{id:1}})
接收方
console.log(this.$route.query.id)
2.vuex
这里也不细说,绝大多数vue2的项目都用vuex来做全局的一个参数存储,例如用户信息,token等等,都离不开vuex
vuex地址:Vuex 是什么? | Vuex
3.Pinia
本质是和vuex是一样的,不过做了优化,在vue3项目中会使用的更多,也可以在vue2中使用
pinia地址:介绍 | Pinia 中文文档
4.Storage
这里是对localStroage和sessionStorage的统称,这两个都是浏览器本身的方法,都具有持久化保存的作用。最具体的就是用户token校验,判断是否登录过的时候,基本都得用Storage。
5.cookie
和Storage差不多的东西,不细说
6.redux
默认是react的配套插件,虽然没见过什么大神在vue中用redux,但是官方介绍确实可以在vue中使用redux。
我是没有操作过,想看的可以参考引用其他人的文档:Redux vue - 老白网络
7.PubSub(万金油)
镇场子的大哥,任何框架,甚至原生都可以使用的一个经典信息传递插件,设计模式的经典之作,跨越语言的存在,别说前端了,你在redis上也都会遇到pubsub.
在使用上和eventbus像,简单好用。我就不费劲写了,直接参考别人的文档吧:一、PubSub 的Vue使用方式_vue pubsub-CSDN博客
结束语
方法有很多,但具体如何使用,看场景,看业务,灵活变通。
其实,不只是props可以实现双向传递参数,$emit和ref都是可以的,你只需要换个思路就可以了,我这里还写了一篇拓展:,使用props,emit和ref实现双向数据通信。
有兴趣的可以去看看:vue2组件通信中的一些拓展(props,emit,ref父子双向传参)-CSDN博客