Vue 组件通信方式全解

Vue 项目中组件通信一直是一个很头疼的问题,本文将会介绍多种组件通信方式。

一、props和$emit


1.1 父组件向子组件传输数据

经常使用 vue.js 的开发者对 props 想必不会陌生,props $emit 的组合是日常运用非常多的一种父子组件间通信的方式。 props 十分符合单项数据流的概念,即数据只能由父组件流向子组件,而子组件不能通过修改父组件通过 props 传过来的值间接的修改父组件。

1.2 单向数据流

为什么这样做,Vue官网中给出的解释是:

所有的 prop 都使得其父子 prop 之间形成了一个单向下行绑定:父级 prop 的更新会向下流动到子组件中,但是反过来则不行。这样会防止从子组件意外改变父级组件的状态,从而导致你的应用的数据流向难以理解。
额外的,每次父级组件发生更新时,子组件中所有的 prop 都将会刷新为最新的值。这意味着你不应该在一个子组件内部改变 prop。如果你这样做了,Vue 会在浏览器的控制台中发出警告。

1.3 子组件通知父组件

单向数据流限制了数据流只能从父组件传递到子组件,那么子组件是否无法影响到父组件呢?这时候就是 $emit 派上用场的时候了。$emit 可以触发绑定在当前这个实例上的事件。即我们可以在父组件中创建个处理状态变化的对应方法,并监听子组件的这个状态变化,在子组件触发这个状态变化时,调用对应的方法。

1.4 示例代码

结果显示:

代码:

// home.vue 父组件

<template>
  <div class="home">
    <h3>Home</h3><button @click="sendDate">prop传值</button>
    {{date}}
    <!-- 通过v-bind绑定在mdate上传递给子组件,date对应父组件实际传递的值 -->
    <!-- 通过v-on绑定dateChanged状态,并确定状态修改的触发事件为 parentChange -->
    <MTitle :mdate="date" @dateChanged="parentChange"/>
    <MNews :mdate="date" @dateChanged="parentChange"/>
    <MFooter :mdate="date" @dateChanged="parentChange"/>
  </div>
</template>

<script>
// @ is an alias to /src
// import MTitle from '@/components/MTitle.vue'
const MTitle = () => import('@/components/MTitle.vue')
const MNews = () => import('@/components/MNews.vue')
const MFooter = () => import('@/components/MFooter.vue')

export default {
  name: 'home',
  components: {
    MTitle,
    MNews,
    MFooter
  },
  data () {
    return {
      date: '1000'
    }
  },
  methods: {
    sendDate: function () {
      this.date = Date.parse(new Date()).toString()
      console.log(this.date)
    },
    parentChange: function (val) {
      this.date = val
    }
  }
}
</script>

// MTitle.vue 子组件

<template>
  <div class="MNews">
    MNews
    <!-- 使用父组件传过来的值 -->
    <div>{{mdate}}</div>
    <button @click="changeDate">修改父组件</button>
  </div>
</template>

<script>
export default {
  name: 'MNews',
  components: {},
  // props 获取父组件传下来的参数
  props: {
    mdate: String
  },
  data () {
    return {
      mes: this.mdate // 子组件不能直接修改父组件的传值,需要赋值
    }
  },
  methods: {
    changeDate: function () {
      this.mes = Date.parse(new Date()).toString()
      this.$emit('dateChanged', this.mes) // 触发状态修改,并传参给父组件,让父组件作出修改动作
    }
  }
}
</script>
<style lang="less">
    .MNews {
        height: 100px;
        background: green;
        color:#fff;
    }
</style>

 

二、事件总线:EventBus


2.1 什么是事件总线

这种方式通过一个创建一个空的 vue 实例 EventBus 作为事件总线,所有的组件都能自由地在这个 EventBus 上监听 ($on) 和修改 ($emit) 状态。从而实现了轻量化的跨组件间数据传递,这种方式可以很好处理父子、兄弟以及跨级组件之间的数据交互。

2.2 核心代码

 var Event=new Vue();
 Event.$emit(事件名,数据);
 Event.$on(事件名,data => {});

2.3 示例代码

结果显示:

代码:

在main.ts中,新构建一个代表事件总线的空 vue 实例,并绑定到 vue 的属性中,以便所有组件都能访问

Vue.prototype.$EventBus = new Vue()

在组件A中:ComA.vue,触发修改姓名事件,去修改组件C的姓名。同时监听组件C可能触发的 reset 事件

<template>
  <div class="">
      组件A {{name}}
      <button @click="changeName">修改C组件的Name</button>
  </div>
</template>

<script>

export default {
  name: 'ComA',
  components: {},
  data () {
    return {
      name: 'benny'
    }
  },
  mounted () {
    // 事件监听一般是在 create 或 mounted 中
    this.$EventBus.$on('resetAll', ({ name, age }) => {
      this.name = name
    })
  },
  methods: {
    changeName () {
      // 发送修改姓名事件
      this.name = 'benny'
      this.$EventBus.$emit('changeName', this.name)
    }
  }
}
</script>

在组件B中:ComB.vue,触发修改年龄事件,去修改组件C的年龄。同时监听组件C可能触发的 reset 事件

<template>
  <div class="">
    组件B {{age}}
    <button @click="changeAge">修改C组件的Age</button>
  </div>
</template>

<script>

export default {
  name: 'ComB',
  components: {},
  data () {
    return {
      age: 10
    }
  },
  mounted () {
    // 事件监听一般是在 create 或 mounted 中
    this.$EventBus.$on('resetAll', ({ name, age }) => {
      this.age = age
    })
  },
  methods: {
    changeAge () {
      // 发送修改年龄事件
      this.age = 10
      this.$EventBus.$emit('changeAge', this.age)
    }
  }
}
</script>

在组件C中:ComC.vue,监听组件A发出的修改名称事件以及组件B发出的修改年龄事件,同时可能触发重置事件,重置姓名和年龄。

<template>
  <div class="">
    组件C {{name}} {{age}}
    <button @click="resetAll">重置name和age</button>
  </div>
</template>

<script>

export default {
  name: 'ComC',
  components: {},
  data () {
    return {
      name: '',
      age: 0
    }
  },
  mounted () {
    // 事件监听一般是在 create 或 mounted 中
    this.$EventBus.$on('changeName', name => {
      this.name = name
    })
    this.$EventBus.$on('changeAge', age => {
      this.age = age
    })
  },
  methods: {
    resetAll: function () {
      // 发送重置事件
      this.name = 'tom'
      this.age = 15
      this.$EventBus.$emit('resetAll', { name: this.name, age: this.age })
    }
  }
}
</script>

 

 

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值