VUE组件通信传值(‘悄悄话’我知道)

2020/4/23 11:51:49

本文主要是介绍VUE组件通信传值(‘悄悄话’我知道),对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

引言


vue的两大特点就是响应式原理组件系统,今天我们就来看一下关于组件系统中各级组件是如何传递数据的。

之后的演示都在如下图的关系网中进行:

Father对于SonDaughter来说为父组件。 Son对于Father为子组件,但是对于 GrandSonBySonGrandDaughterBySon为父组件。 Daughter对于Father为子组件,但是对于 GrandSonByDau为父组件。 同时,DaughterSon有同一个父组件 Father因此这两个组件互为兄弟组件

一、使用prop(父传子)和$emit(子传父)

父组件通过子组件暴露的prop的sonValue、dauValue向子组件传值。

//父组件
<template>
  <div class="father">
    <son v-bind:sonValue="son"></son>
    <daughter v-bind:dauValue="daughter"></daughter>
  </div>
</template>
<script>
import Daughter from '@/views/Daughter.vue'
import Son from '@/views/Son.vue'
export default {
  components: {
    Daughter,
    Son
  },
  data () {
    return {
       son:'son',
       daughter:'daughter'
    }
  }
}
</script>
复制代码

子组件通过内部定义的props接收到父组件的值,每当父组件的值变化的时候,子组件内部的值就会发生变化,可以使用this.[props]来进行引用。

// 子组件
<template>
  <div class="father">
    {{sonValue}}  <!-- son -->
  </div>
</template>
<script>
export default {
  props:{
    sonValue:{
      type:String,
      default:""
    }
  },
  data () {
    return {

    }
  },
  mounted(){
    console.log(this.sonValue) // 父组件输入的值'son'
  }
}
</script>
复制代码

子组件向父组件传值其实就是触发事件然后通过事件传参返回给父组件。

// 子组件中触发
this.$emit('事件名','值')
复制代码
// 父组件中将事件绑定回父实例的函数上,第一个参数为子组件的传值。
<son v-bind:sonValue="son" @changeFather="change"></son>

methods:{
    change(value){
       //value是子组件的传过来的值
       this.fromSon = value
    }
}
复制代码

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

  // 子组件son的修改
  data () {
    return {
       //初始化一个子组件内部的值,将传入的值赋值。
       realSonValue:this.sonValue
    }
  },
复制代码

二、vm.$ref.[child]vm.$parent(父子组件之间的显示调用)

vm.$ref.[child]在父组件中引入子组件并且设置子组件的ref值。ref="son"

// 父组件
<template>
  <div class="father">
    <son v-bind:sonValue="son" @changeFather="change" ref="son"></son>
    {{fromSon}}
    <daughter v-bind:dauValue="daughter"></daughter>
  </div>
</template>
// 父组件都可以通过引用'ref'的方式来获得。
mounted(){
    console.log(this.$refs.son.innerValue) // '$refs.son'
    this.$refs.son.innerFun() // 'I am Son'
}
复制代码

子组件内部定义的一个值、或者方法。

data () {
    return {
       // 初始化一个子组件
       innerValue:'$refs.son'
    }
},
methods:{
    innerFun(){
      console.log('I am Son')
    }
},
复制代码

vm.$parent在子组件中引入父组件实例

// 父组件
data () {
    return {
       innerFather:'vm.$parent'
    }
},
复制代码
// 子组件
mounted(){
    console.log(this.$parent.innerFather) // ·'vm.$parent'
}
复制代码

注意:有的小伙伴会发现一个问题就是既然有vm.$parent那应该也有vm.$children结果一试还真有,但是在vm中你会发现,一个父组件可以有很多个子组件,也就是有vm.$children使用这个打印出来的是一个子组件的类数组,无法定位到你要子组件的值,但是每个子组件只有一个父组件这个是固定的。

三、bus总线机制(兄弟组件之间)

通过vm.$emitvm.$on通过 vm.$emit 触发当前实例上的事件,并将参数传递给监听器,通过 vm.$on 监听当前实例上的自定义事件。

简单理解为一个托管平台,这个平台必须独立于关联两个组件之外的一个vue实例,当两个组件需要传递数据的时候,发起方在平台上触发一个vm.$emit然后传递参数,接收方在平台设置一个监听vm.$on接收参数并且执行方法,方法的参数就是发送方传递过来的参数。

先定义一个托管平台,vue项目中你可以以单文件的形式在各个兄弟组件中引入,或者像我一样生成一个vue实例挂在整个Vue实例之下。

var bus = new Vue()
Vue.prototype.bus = bus
复制代码
// 发送方兄弟组件触发$emit设置名字以及传递参数
mounted(){
    this.bus.$emit('SonByDauChange','I am grandSonByDau')
}
复制代码
// 接收方兄弟组件监听事件,并执行回调
methods:{
    brotherData(value){
      console.log(value) // 'I am grandSonByDau'
    }
},
mounted(){
    this.bus.$on('SonByDauChange',this.brotherData)
}  
复制代码

四、vm.$attrsvm.$listeners

props和emit的父子组件传值的进化版。可以从父组件到孙组件的跨级传递,中间的子组件作为vm.$attrsvm.$listeners的实现载体

vm.$attrs 存放了没有被子组件props所标记的属性,即可以理解为父组件在子组件上自己绑定的数据

//  父组件引入son子组件
<div>这是父组件</div>
<Son :myData="value" :grandSon="grandSon" @changeGrandSon="changeGrandSon"></Son>
data () {
    return {
      myData:'from props',
      grandSon:'from father'
    };
},
methods: {
    changeGrandSon(value){
      console.log(value) // from grandSon
    }
},

// 子组件,能在父组件中被引用的是myData的值,但是我们能通过vm.$attr对象获得props之外的属性
<div>这是子组件</div>
<grandSon v-bind="$attrs" v-on="$listeners"></grandSon> // 划重点可以将父组件给予子组件prop的额外的值传递给孙组件
props:{
      myData:{
        type:String,
        default:''
}
mounted() {
    console.log(this.$attrs.granSon) //可以获得from father
},

// 孙组件,不需要props可以直接获得从父组件传递过来的值
<div>这是孙组件</div>
<div>{{$attrs.grandSon}}</div> // from father
 mounted() {
    console.log(this.$attrs)
    this.$emit('changeGrandSon','from grandSon') // 触发父组件的changeGrandSon的事件
},
复制代码

总结:vm.$attrsvm.$listeners都可以实现从父组件将值和事件跨级(上下游,兄弟组件不可)传递,但是在中间的组件(子组件)需v-bind="$attrs" v-on="$listeners"要绑定传值。

五、provide / inject

这对选项需要一起使用,以允许一个祖先组件向其所有子孙后代注入一个依赖,不论组件层次有多深,并在起上下游关系成立的时间里始终生效。只有数据向下传递,并没有事件响应向上。可以向下跨级传递,子、孙只要有inject均可。

// 父级组件提供 'foo'
var Provider = {
  provide: {
    foo: 'bar'
  },
  // ...
}

// 子、孙组件注入 'foo'
var Child = {
  inject: ['foo'],
  created () {
    console.log(this.foo) // => "bar"
  }
  // ...
}
复制代码

六、结束

单纯提出想法,中间可能有坑更多的实际操作需要各位亲自去尝试,结合api文档。



这篇关于VUE组件通信传值(‘悄悄话’我知道)的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程