vue组件通信

整理了vue中组件通信,分以下情况:(代码环境:vue2.0  vue-cli 3.0.1)

一:父--》子通信

1、通过props:

//子组件
<template>
  <div class="son">{{msg}}</div>
</template>
<script>
export default {
  name: 'son',
  props:{
    msg:String
  }
 }
</script>
//父组件
<template>
  <div class="parent">
    <son :msg="myName"></son>
  </div>
</template>

<script>
import son from '../components/son'
export default {
  name: 'parent',
  components:{
    son
  },
  data() { 
    return {
      myName:'hello world'
    }
  }
 }
</script>

以上就是将父组件parent中的myName传入到了子组件son中

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

二:子--》父

通过事件,使用$emit触发,具体看以下代码:

//子组件
<template>
  <div class="son" >
    <button @click="getNum">click</button>
  </div>
</template>

<script>
export default {
  name: "son",
  data() {
    return {
      num:6666
    };
  },
  methods: {
    getNum() {
     this.$emit('getNum',this.num)
    }
  }
};
</script>
//父组件
<template>
  <div class="parent">
    <son @getNum="getNum"></son>
  </div>
</template>

<script>
import son from '../components/son'
export default {
  name: 'parent',
  components:{
    son
  },
  methods:{
    getNum(e){
      console.log(e)//可以获取到子组件中的num值
    }
  }
 }
</script>

三:其实父子组件通信还可以使用vm.$refs  一个对象,持有注册过 ref特性 的所有 DOM 元素和组件实例。

//父组件   通过调用子组件的方法,以参数的形式传入到子组件中;同样的子组件也可以使用方法将值传到父组件中
<template>
  <div class="parent">
    <son ref="son"></son>
  </div>
</template>
<script>
import son from '../components/son'
export default {
  name: 'parent',
  components:{
    son
  },
  data() { 
    return {
      myName:'hello world'
    }
  },
  mounted(){
    this.$refs.son.getName(this.myName)
   console.log(this.$refs.son.getNum())//输出的就是子组件中num值 } }
</script>
//子组件
<template>
  <div class="son"> </div>
</template>
<script>
export default {
  name: "son",
 data(){return {num:123}}, methods: { getName(e) { console.log(e)
//e就是传入的myName值 },
  getNum(){
    return this.num
  }
} };
</script>

注意:根据官方文档 $refs 只会在组件渲染完成之后生效,并且它们不是响应式的。这仅作为一个用于直接操作子组件的“逃生舱”——你应该避免在模板或计算属性中访问 $refs

因此还是不建议使用ref来进行父子之间的数据传递;

四:非父子组件中的数据传递

1、路由url传递

  • 在传统开发时我们常常把需要跨页面传递的数据放到url后面,跳转到另外页面时直接获取url字符串获取想要的参数即可,在vue跨组件时一样可以这么做,

    // router index.js 动态路由
    {
       path:'/params/:Id',
       component:Params,
       name:Params
    }
    // 跳转路由
    <router-link :to="/params/12">跳转路由</router-link>
  • 在跳转后的组件中用$route.params.id去获取到这个id参数为12,但这种只适合传递比较小的数据,数字之类的

2、 eventBus通信   

   eventBus这种通信方式,针对的是非父子组件之间的通信,它的原理还是通过事件的触发和监听。

  但是因为是非父子组件的关系,他们需要有一个中间组件来连接。

  使用eventBus传递数据,我们一共需要做3件事情

  • 1.在组件之外定义一个bus.js作为组件间通信的桥梁,适用于比较小型不需要vuex又需要兄弟组件通信的,或者给app组件添加Bus属性 (这样所有组件都可以通过this.$root.Bus访问到它,而且不需要引入任何文件)
  • 2.在组件1里,this.$root.Bus.$emit触发事件
  • 3.在组件2里,this.$root.Bus.$on监听事件
    //bus.js
    import Vue from 'vue'
    export default new Vue()
    /*
    或者在main.js中添加Bus属性
    import Vue from 'vue'
    new Vue({
      el: '#app',
      components: { App },
      template: '<App/>',
      data(){
        return {
          Bus : new Vue()
        }
      }
    })
    通过this.$root.Bus.$emit()/.$on()来处理
    */
    //组件1
    <template>
      <div class="home">
          <button  @click="handlerClick">clickBus</button>
      </div>
    </template>
    
    <script>
    // @ is an alias to /src
    import Bus from '../models/bus'
    export default {
      name: "home",
      methods:{
        handlerClick(){
    Bus.$emit(
    'handlerClick','兄弟组件传递参数')
    } } }; </script>
    //组件2
    <template>
    <div class="about">
        <h1>This is an about page</h1>
      </div>
    
    </template>
    <script>
    import Bus from '../models/bus'
    export default {
      data(){
        return {}
      },
      mounted(){
        Bus.$on('handlerClick',(e=>{
    console.log(e) })) } }; </script>

    注意:首屏渲染完之后,没有进入组件2,在组件1中直接点击handlerClick按钮时,并不会触发组件2中的clickBus事件,可能是这时候组件2并没有渲染事件并没有绑定,无法触发

五:祖--》孙

  如果跨组件传递通过以上一步步的传递是比较麻烦的,可以使用$attr来实现祖孙之间的传递

  意思就是父组件传向子组件传的,子组件不prop接受的数据都会放在$attrs中,子组件直接用this.$attrs获取就可以了。如过从父->孙传,就在子组件中添加v-bind='$attrs',就把父组件传来的子组件没props接收的数据全部传到孙组件,具体看以下代码

//祖组件
<template>
  <div class="grandFather">
<parent :number="num" :output="myName"></parent>
  </div>
</template>

<script>
import parent from './Parent'
export default {
  name: 'grandFather',
  components:{
    parent
  },
  data() { 
    return {
      num:666,
      myName:'grandFather'
    }
  }
 }
</script>
//父组件
<template>
  <div class="parent">
    <son v-bind="$attrs" ></son>
  </div>
</template>

<script>
import son from '../components/son'
export default {
  name: 'parent',
  components:{
    son
  },
  props:{
    number:Number//这里在父组件中定义了number,因此在父组件以及子组件中this.$attrs无法获取number值
  },
 mounted(){
   console.log(this.$attrs)//打印output
 }
 }
</script>
//子组件
<template>
  <div class="son" >
   son
  </div>
</template>

<script>
export default {
  name: "son",
  mounted(){
    console.log(this.$attrs)//打印output
  }
};
</script>

得到一下输出结果:

 

六:其他的通信方式

1、用localStorage或者sessionStorage这种通信比较简单,缺点是数据和状态比较混乱,不太容易维护。

  通过window.localStorage.getItem(key) 获取数据
  通过window.localStorage.setItem(key,value) 存储数据

  注意用JSON.parse() / JSON.stringify() 做数据格式转换。

2、provide/inject还有$children/$parent 

3、使用vuex

参考文章:

整理4种Vue组件通信方式

vue组件通信全面总结

以上是根据上面两篇文章进行的总结,如果看不懂可以访问原链接,原文里面也有其他的方法可以参考,有错误的地方希望可以提出。

posted @ 2019-04-03 18:01  H-LI  阅读(196)  评论(0编辑  收藏  举报