你想要知道的Vue组件间数据传递的方式

4,560 阅读4分钟

vue中传递数据的方式有哪些

数据流的方式传递数据

通过 props 传递属性

父级给child组件绑定一个msg数据

父组件

<template>
  <div class='container'>
    <child :msg="msg" @change="change" />
  </div>
</template>

<script>
import child from './demo2'
export default {
  data(){
    return {
      msg:'这是测试数据'
    }
  },
  methods:{
    change(value){
      this.msg = value
    }
  },
  components: {
    child
  }
}
</script>

子组件通过定义props来使用msg,$emit触发外部的函数来改变父级传入的值

子组件

<template>
  <div class='container'>
    {{msg}}
    <button @click="change">点一下</button>
  </div>
</template>

<script>
export default {
  props:['msg'],
  methods:{
    change(){
      this.$emit('change','这是新的数据')
    }
  }
}
</script>

上述步骤可以通过.sync修饰符进行简写

父组件

<template>
  <div class='container'>
      <child :msg.sync="msg"/>
  </div>  
</template>

<script>
import child from '@/components/demo'
export default {
  data () {
    return {
      msg:"外部传的msg",
    }
  },
  components: {
    child
  }
}
</script>

子组件

<template>
  <div class='container'>
    <div>{{msg}}</div> 
    <button @click="change">点一下改变</button>
  </div>

</template>

<script>
export default {
  props:{
    msg:String,
  },
  methods: {
    change(){
      // 触发update:属性名来更新
      this.$emit("update:msg",'改变后的msg')
    }
  },
}
</script>


v-bind:prop.sync可以绑定一个对象,会默认将对象中的属性作为prop传递给组件

父组件

<template>
  <div class='container'>
      <child :data.sync="data"/>
  </div>  
</template>

<script>
import child from '@/components/demo'
export default {
  data () {
    return {
      data:{
        msg: '外部传的msg',
        text:'外部传的text',
        value:'外部传的value'
      },
    }
  },
  components: {
    child
  }
}
</script>

子组件

<template>
  <div class='container'>
    <div>{{data.msg}}</div> 
    <div>{{data.text}}</div> 
    <div>{{data.value}}</div> 
    <button @click="change">点一下改变</button>
  </div>

</template>

<script>
export default {
  props:{
    data:Object,
  },
  methods: {
    change(){
      this.$emit("update:data",{
        msg:'改变后的msg',
        text:'改变后的text',
        value:'改变后的value'
        })
    }
  },
}
</script>


通过 $attrs 来收集属性

$attrs 会收集组件上绑定的属性,对应class和style不会处理。如果与props同用,props的优先级要高于attrs

父组件

<template>
  <div class="container">
    <child class="demo" style="color:red" :msg="msg" />
  </div>
</template>

<script>
import child from "./demo2";
export default {
  data() {
    return {
      msg: "这是测试数据"
    };
  },
  components: {
    child
  }
};
</script>

子组件中this.$attrs会收集组件上绑定的属性

子组件

<template>
  <div class="container">{{$attrs.msg}} </div>
</template>

<script>
export default {
  // inheritAttrs:true,
  // 会隐藏行间的属性
  // props:['msg'],
  // 这里props的优先级比$attrs要高,如果设置了props,那么msg会在data上,而$attrs中就没有msg
  created(){
    console.log(this.$attrs)
    // 对象中只有msg一个属性
  }
};
</script>

通过$listeners 来收集方法

$listeners 会收集组件上绑定的方法。 可以通过传递实参的方式改变父组件的值

父组件

<template>
  <div class='container'>
    {{msg}}
    <child class="demo" style="color:red" @msgChange="change"/>
  </div>
</template>

<script>
import child from './demo2'
export default {
  data () {
    return {
      msg: '这是测试数据'
    }
  },
  methods: {
    change(newvalue){
      this.msg = newvalue;
    }
  },
  components: {
    child
  }
}
</script>

子组件中this.$listeners会收集绑定在组件上的方法。通过this.$listeners.XXX()可以直接调用,以此可以来修改父组件data中的值

子组件

<template>
  <div class="container">
    <button @click="change">点一下</button>
  </div>

</template>

<script>
export default {
  // inheritAttrs:true,
  created(){
    console.log(this)
  },
  methods:{
    change(){
      // this.$emit('msgChange')
      // this.$parent.change()
      // 与$emit功能相同,$parent也能够实现该效果

      this.$listeners.msgChange('改变后的值')

    }
  }
};
</script>

通过provide提供依赖,inject注入依赖实现数据跨多级子组件传递

通过给父级的 provide 提供一个依赖对象,让其所用子组件都能访问到这个对象

provide 和 inject 绑定并不是可响应的。这是刻意为之的。然而,如果你传入了一个可监听的对象,那么其对象的 property 还是可响应的。

其实也就是说provide 和 inject 绑定本身不做额外的事情(数据绑定之类),只是将提供的数据暴露给子组件。那么暴露出来的数据是不是可相应的就取决与数据本身

父组件

<template>
  <div class='container'>
    <child class="demo" style="color:red"  :msg="msg" @msgChange="change"/>
  </div>
</template>

<script>
import child from './demo2'
export default {
  provide(){
    return {
      msg:this.msg,
      msgChange:this.change,
      // 这里this本身就是一个可监听的对象。
      // this也就是当前vue实例本身已完成了数据响应,这里只是将这个实例暴露给了他的所用子组件
      app:this
    }
  },
  data () {
    return {
      msg: '这是测试数据'
    }
  },
  methods: {
    change(){
      this.msg += 1;
    }
  },
  components: {
    child
  }
}
</script>

后代的子组件可以通过reject注入相应的依赖

子组件

<template>
  <div class="container">
    <!-- 这个msg的值不会变 -->
    <div>{{msg}} </div>
    <!-- msg的值会变,因为依然指向父组件的vue实例 -->
    <div>{{app.$data.msg}}</div>
    <button @click="msgChange">点一下</button>
  </div>
</template>

<script>
export default {
  inject:['msg','msgChange','app']
};
</script>

直接访问组件实例的方式获取数据

通过 ref 获取组件实例

ref 属性定义在组件上获取的是组件的vue实例,定义在原生标签上获取的是对应的dom

需要等挂载之后才能拿到$refs中的内容

父组件

<template>
  <div class='container'>
    {{msg}}
    <child ref="test"/>
  </div>
</template>

<script>
import child from './demo2'
export default {
  data () {
    return {
      msg: ''
    }
  },
  // 需要等挂载之后才能拿到$refs中的内容。
  // 所用不能在模板中使用
  mounted(){
    this.msg = this.$refs.test.msg
  },
  components: {
    child
  }
}
</script>

子组件

<script>
export default {
  data(){
    return {
      msg:'这是子组件的数据'
    }
  }
}
</script>

通过\$parent/$children 获取组件实例

同样的也是必须在mounted之后才能获取对应实例

这里是父组件展示子组件中的msg,子组件展示父组件的msg

父组件通过$children获取子组件实例

父组件

<template>
  <div class='container'>
    {{msg}}
    <child/>
  </div>
</template>

<script>
import child from './demo2'
export default {
  data () {
    return {
      msg: '',
      fatherMsg:"这是父组件的内容"
    }
  },
  mounted(){
    console.log(this.$children)
    //获取子组件实例上的sonMsg,$children是个数组需要选择对应的索引
    this.msg = this.$children[0].sonMsg;
  },
  components: {
    child
  }
}
</script>

子组件通过$paren获取父组件实例

子组件

<template>
  <div class='container'>
    {{msg}}
  </div>
</template>

<script>
export default {
  data () {
    return {
      msg:'',
      sonMsg: '这是子组件的数据'
    }
  },
  mounted(){
    //获取父组件的实例上的fatherMsg
    this.msg = this.$parent.fatherMsg;
  }
}
</script>

定义一个公共仓库共享数据

定义 eventBus 共享数据

在Vue原型上添加一个$bus为一个新的vue对象,可以在全局的vue实例中通过$bus获取到这个vue对象,从而获取这个对象上的属性和方法。

main.js中定义

Vue.prototype.$bus = new Vue({
  data:{
    a:1,
    b:2
  },
  methods:{
    log(){
      console.log(this.a)
    }
  }
})

全局Vue实例都能获取到定义在$bus上的属性和方法

通过 Vuex 共享数据

官方给出的跨多组件传递数据的解决方案。

store index.js

import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

export default new Vuex.Store({
  state: {
    test:'123123123',
    test2:'123123123',
  },
  mutations: {
    changeTest(state,payload){
      console.log(state,payload)
      state.test = payload.value
    },
    changeTest2(state,payload){
      console.log(state,payload)
      state.test2 = payload.value
    }
  },
  actions: {
    asyncChageTest({commit},payload){
      setTimeout( ()=>{
        commit('changeTest2',payload)
      },2000)
    }
  },
  modules: {
  }
})

在组件中使用

<template>
  <div class='container'>
    {{this.$store.state.test}}
    {{test}}
    {{this.$store.state.test2}}
    {{test2}}
    <button @click="change">点一下</button>
    <button @click="asyncChange">点一下</button>
  </div>
</template>

<script>
// 引入mapState辅助函数改造state数据
import { mapState,mapMutations,mapActions } from 'vuex'
export default {
  data(){
    return {
      msg:'这是测试数据'
    }
  },
  computed:{
    ...mapState(['test','test2'])
  },  
  methods:{
    // 放异步或者同步的方法引入
    ...mapMutations(['changeTest']),
    ...mapActions(['asyncChageTest']),
    change(){
      // 同步修改state值的两种方法
      this.$store.commit('changeTest',{value:'改变后test的值'});
      // this.changeTest({value:'改变后的值'})
    },
    asyncChange(){
      // 异步修改state值的两种方法
      this.$store.dispatch('asyncChageTest',{value:'改变后test2的值'})
      // this.asyncChageTest({value:'改变后test2的值'})
    }
  },
}
</script>

以上就是对Vue中组件间数据传递的方式进行了一个总结,在日常的开发中还是需要根据使用的场景采取合适的方式进行数据的传递