组件之间共享数据的方式常用的有:

1, props 属性传递数据
2, emit 事件
   a: 全局的eventHub机制
   b: 父组件调用子组件使用v-on:eventName="handleFunc",子组件在需要的时候调用this.$emit(eventName, params)即可。
3, vuex
4, ref 父组件给子组件添加一个ref引用,<child-component ref=”child“ /> 直接通过this.$refs.child获取到子组件实例对象。 如果在普通的 DOM 元素上使用,引用指向的就是 DOM 元素。
5, $parent / $children 当前组件的父组件 和子组件

6, 通过provide 和 inject 来实现共享数据

provide 和 inject 类似于react的 Context共享数据, 父组件 与【子孙】组件而不只是子组件共享,有跨层级。

假定我们有3个组件。 Parent -> Child -> GrandSon 分别为父组件,子组件,孙子组件。
其实基础的用法都知道,在父组件Parent里面这样写:


import Child from './Child'
export default {
  name: 'Parent',
  provide: {
	nameFromParent: 'Kevin'
  }
  components: {
    Child
  }
}

在GrandSon组件里面这样写[Child组件的调用忽略]:

export default {
  inject: ['nameFromParent'],
  mounted () {
    console.log(this.nameFromParent, 'nameFromParent')
  }
}

这样在加载GrandSon组件的时候会发现this.nameFromParent的值为Kevin,和父组件里面的定义的一致。


但是实际需求肯定没有这么简单,往往我们需要的是共享父组件里面的动态数据,这些数据可能来自于data 或者 store。 就是说父组件里面的数据发生变化之后,需要同步到子孙组件里面。这时候该怎么做呢?

我想的是将一个函数赋值给provide的一个值,这个函数返回父组件的动态数据,然后在子孙组件里面调用这个函数。
实际上这个函数存储了父组件实例的引用,所以每次子组件都能获取到最新的数据。代码长下面的样子:

Parent组件:

<template>
    <div class="parent-container">
      Parent组件
      <br/>
      <button type="button" @click="changeName">改变name</button>
      <br/>
      Parent组件中 name的值: {{name}}
      <Child  v-bind="{name: 'k3vvvv'}" />
    </div>
</template>

<style scoped>
  .parent-container {
    padding: 30px;
    border: 1px solid burlywood;
  }
</style>

<script>
import Child from './Child'
export default {
  name: 'Parent',
  data () {
    return {
      name: 'Kevin'
    }
  },
  methods: {
    changeName (val) {
      this.name = 'Kev'
    }
  },
  provide: function () {
    return {
      nameFromParent: this.name,
      getReaciveNameFromParent: () => this.name
    }
  },
  // provide: {
  // nameFromParent: this.name,
  // getReaciveNameFromParent: () => this.name
  // },
  components: {
    Child
  }
}
</script>

Child组件

<template>
  <div class="child-container">
    Child组件
    <br/>
    <GrandSon />
  </div>
</template>
<style scoped>
  .child-container {
    padding: 30px;
    border: 1px solid burlywood;
  }
</style>
<script>
import GrandSon from './GrandSon'
export default {
  components: {
    GrandSon
  }
}
</script>

GrandSon组件:

<template>
  <div class="grandson-container">
    Grandson组件
    <br/>
    {{nameFromParent}}
    <br/>
    {{reactiveNameFromParent}}
  </div>
</template>
<style scoped>
  .grandson-container {
    padding: 30px;
    border: 1px solid burlywood;
  }
</style>
<script>
export default {
  inject: ['nameFromParent', 'getReaciveNameFromParent'],
  computed: {
    reactiveNameFromParent () {
      return this.getReaciveNameFromParent()
    }
  },
  watch: {
    'reactiveNameFromParent': function (val) {
      console.log('来自Parent组件的name值发生了变化', val)
    }
  },
  mounted () {
    console.log(this.nameFromParent, 'nameFromParent')
  }
}
</script>


点击 改变name 按钮,查看效果如下:

在这里插入图片描述
第一个kevin 是来自于非响应式的 provide变量 nameFromParent

第二个来自于reactiveNameFromParent ,随着祖先组件变化而变化了

Logo

前往低代码交流专区

更多推荐