Vue组件通信

788 阅读1分钟

父子组件通信

1. props

父组件给子组件添加属性 :fatherName="name" 传值,子组件通过props:['fatherName'] 接收; 子组件可以通过 this.$emit('changeFatherName','吴彦祖') 向父组件发送事件和数据, 父组件通过 @changeFatherName="changeFatherName" 监听事件和传递过来的数据

2. sync/update

v2.3新增语法糖,会扩展成一个更新父组件绑定值的 v-on侦听器;

<son :fatherName.sync="name" ref="son"></son> 子组件update:propName直接修改数据,父组件无需定义监听事件来接收数据 this.$emit('update:fatherName', '吴彦祖') 适合基本数据类型的传递和修改

3. provide/inject

父组件通过provide:{fatherAge:30}传值,子组件通过inject:["fatherAge"]接收,provide传递的数据, 不仅所有子组件都可以接收,所有后代组件均可以通过inject接收到

4. $attrs/$listeners

v2.4新增

$attrs 包含了父作用域中不作为 prop 被识别 (且获取) 的属性绑定 (class 和 style 除外)。 例如,父组件传递了 fatherName,fatherAge,fatherJob 三个属性 而子组件只通过props接收了fatherName 属性 子组件会默认渲染成<div fatherage="30" fatherjob="engineer"></div> inheritAttrs:false 可以阻止这种默认行为, 子组件可以通过 v-bind="$attrs" 将这些属性传递给孙组件,相当于:fatherAge="$attrs.fatherAge" :fatherJob="$attrs.fatherJob"

$listeners 包含了父作用域中的 (不含 .native 修饰器的) v-on 事件监听器,它可以通过 v-on="$listeners" 传入内部组件 本例中子组件 可以用$listeners将父组件的changeFatherName事件监听传递给孙组件,使孙组件可以跨级修改父组件data

5. $children/$parent

父组件通过$children访问子组件属性和方法,子组件通过$parent访问父组件属性和方法, this.$children[0].age=2 修改子组件数据,同理this.$parent.age=30 修改父组件数据

6. ref/refs

子组件绑定ref属性,父组件通过this.$refs['xxx']访问子组件,用法和 $children 相同; 本例中this.$refs['son']===this.$children[0] //true

//父组件
<template>
  <div>
    <h3>爸爸:</h3>
    <div>姓名:{{ name }}</div>
    <div>年龄:{{ age }}</div>
    <button @click="seeSon">看看儿子</button>
    <son
      :fatherName="name"
      :fatherAge="age"
      :fatherJob="job"
      @changeFatherName="changeFatherName"
      ref="son"
    ></son>
    <!-- <son :fatherName.sync="name" ref="son"></son> -->
  </div>
</template>
<script>
import son from './son.vue'
export default {
  components: {
    son,
  },
  provide:{
    fatherAge:30
  },
  data() {
    return {
      name:'father',
      age:30,
      job:'engineer'
    }
  },
  methods:{
    seeSon(){
      // console.log(this.$refs['son']===this.$children[0]) //true
      this.$children[0].age=2 //修改子组件数据
      console.log(this.$children[0].age) //1 = 2
    },
    changeFatherName(val){
      this.name=val
    }
  }
}
</script>
//子组件
<template>
  <div>
    <h3>{{ `儿子:我爸爸是${fatherName}; 今年${fatherAge}岁` }}</h3>
    <div>姓名:{{ name }}</div>
    <div>年龄:{{ age }}</div>
    <button @click="seeFather">看看爸爸</button>
    <button @click="changeFatherName">给爸爸改名字</button> 
    <grandson v-bind="$attrs" v-on="$listeners"></grandson>
  </div>
</template>
<script>
import grandson from './grandson.vue'
export default {
  components: {
    grandson,
  },
  props: ['fatherName'],
  inject: ['fatherAge'],
  inheritAttrs:false,
  data() {
    return {
      name:'baby',
      age:1
    }
  },
  methods:{
    seeFather(){
      console.log(this.$parent.age) //30
    },
    changeFatherName() {
      this.$emit('changeFatherName','吴彦祖')
      //this.$emit('update:fatherName', '吴彦祖')
    }
  },
  created(){
    console.log(this.$attrs) // { "fatherAge": "30", "fatherJob": "engineer" }
  }
}
</script>
//孙组件
<template>
  <div>
    <h3>{{ `孙子:我爷爷今年${fatherAge}岁;是一个${fatherJob}; ` }}</h3>
    <button @click="changeFatherName" >给爷爷改名字</button> 
  </div>
</template>
<script>
export default {
  props: ['fatherJob'],
  inject: ['fatherAge'],
  inheritAttrs:false,
  methods:{
    changeFatherName () {
      this.$emit('changeFatherName','孙子的爷爷')
    },
  },
  created(){
    console.log(this.$attrs) // { "fatherAge": "30" }
  }
}
</script>

7. 子组件直接修改props/inject传过来的值

  • 如果props基本数据类型,子组件中的prop会变化,父组件中不会变化且控制台会报错
  • 如果props引用数据类型,父组件和子组件都会成功修改且不会报错(不建议这么做)

非父子组件、兄弟组件之间的数据传递

Vuex

详见官方文档vuex.vuejs.org/zh/ 后面补一篇Vuex原理,再详细整理😄

EventBus

eventBus 又称为事件总线,在vue中可以使用它来作为沟通桥梁的概念, 就像是所有组件共用相同的事件中心, 可以向该中心注册发送事件或接收事件, 所有组件都可以通知其他组件。 (维护困难,eventName起名字困难,不易维护,不及时注销事件会产生各种问题,复杂项目中还是使用Vuex)

//新建一个Vue实例作为中央事件总线
let EventBus = new Vue();
//监听事件
EventBus.$on('eventName', (val) => {
//......do something
});
//触发事件
EventBus.$emit('eventName', 'this is a message.');
//移除事件
EventBus.$off('eventName', {})

localStorage/sessionStorage

本地存储,某些业务中使用较多,比如记住用户tocken 系统设置等 window.localStorage.getItem(key) 获取数据,通过 window.localStorage.setItem(key,value) 存储数据; 注意:value只能值字符串类型,需要用JSON.parse() / JSON.stringify() 转换 sessionStorage同理

总结

  • 父子组件通信: props; .sync/updateprovide/inject ; $parent/$children; ref/refs; $attrs/$listeners

  • 非父子组件/兄弟组件通信: EventBus ; Vuex;localStorage/sessionStorage