vue常见组件间通信方式

1.父组件向子组件通信:

总结:父组件通过props向下传递数据给子组件。注:组件中的数据共有三种形式:data、props、computed。

通信步骤:

      1.1  在父组件中定义要传递的数据。

      1.2 在父组件中调用子组件,并在组件上进行属性绑定,前者自定义名称便于子组件调用,后者是要传递的数据名称。

      1.3  在组件件中通过props对象进行接收。

//父组件App组件

<template> 

     <div id="app">

         //1.2 在父组件中调用子组件,并在组件上进行属性绑定,前者自定义名称便于子组件调用,后者是要传递的数据名称。前者childs1是自定义名称便于子组件调用,后者childs2是要传递数据名

         <childs :childs1="childs2"></childs>

     </div>

</template>

<script>

import Childs from "./components/childs";

export default {

     name: 'App',

     data(){

         return{

            //1.1  在父组件定义数据。

             childs:["Henry","Bucky","Emily"]

         }

      },

     components:{ childs,}

}

</script>

//子组件 childs

<template>

     <div class="hello">

         <ul>

              //遍历传递过来的值childs1,然后呈现到页面

             <li v-for="child in childs1">{{child }}</li>

         </ul>

     </div>

</template>

<script>

export default {

     name: 'Childs',

     //1.3 在组件件中通过props对象进行接收。

     props:{

         childs1:{  //这个就是父组件中子标签自定义名字

              type:Array,

              required:true

         }

     }

}

</script>

 

2.子组件向父组件通信:

总结:子组件通过$event给父组件发送消息,实际上就是子组件把自己的数据发送到父组件。通过事件形式。

通信步骤:     

       2.1  在子组件中定义要传递的数据。

       2.2 在子组件中 methods 中定义一个函数,函数内部通过 .$emit(‘定义事件名称 childData’,‘要传递的数据 title’)向父组件传递数据。

       2.3 在子组件中 将这个函数绑定到点击事件上。

       2.4 在父组件中在调用的子组件上同样进行事件绑定,与子组件名称可以不同。

       2.5 在父组件中methods 中,用这个绑定的事件去获取数据。

 

//子组件childs

<template>

     <childs>

          //2.3 在子组件中 将这个函数绑定到点击事件上。

         <h1 @click="childData">{{title}}</h1>

     </childs>

</template>

<script>

export default {

     name: 'Childs',

     data() {

         return {

             //2.1在子组件中定义要传递的数据。

             title:"Vue.js Demo"

         }

     },

     methods:{

             changeTitle() 

                      let _this. = this

                     //2.2 在子组件中 methods 中定义一个函数,函数内部通过 .$emit(‘定义事件名称 childData’,‘要传递的数据 title’)向父组件传递数据。

                     _this.$emit("childData", this.title)

             }

     }

}

</script>

//父组件App

 <template>

     <div id="app">

          //2.4 在父组件中在调用的子组件上同样进行事件绑定,与子组件名称可以不同。

         <childs @titleChanged="updateTitle($event)" ></childs>

         <h2>{{title}}</h2>

     </div>

</template>

<script>

import Childs from "./components/childs";

export default {

     name: 'App',

     components:{

         childs

     }

     data(){

             return{

                 title: ""

             }

     },

    methods:{

          //2.5 在父组件中methods 中,用这个绑定的事件去获取数据。

         updateTitle(e){

              let _this. = this

             _this.title = e

         }

     }

}

</script>

3.跨级组件间的通信:

总结:多级组件嵌套需要传递数据时,通常使用的方法是通过vuex。但如果仅仅是传递数据,而不做中间处理,可以使用$attrs/$listeners。当前组件已接收的属性指的是当前组件在props中声明的属性。

$attrs:表示<父组件传递的属性集合>与<当前组件已接收的属性集合>的差集,也就是说已被当前组件接收的属性,在下面的层级中无法再获取到$attrs的值与inheritAttrs的值无关。

inheritAttrs: 默认true,也就是说当前组件如果没有在props中声明的剩余属性会继承到原始html元素的属性值上,改为false,在当前组件中props中没有声明的多余属性不会继承到原始html元素的属性。

$listeners是子组件通过$emit提交的所有事件集合 (由于冒泡,还包含子组件从下一层组件获得的所有事件),和$attrs不同的是,即使当前组件处理了子组件提交的某个事件,父组件仍然能获取到这个事件并处理,它应该是遵循了事件冒泡的原则。

使用步骤:

          1.  在父级组件进行属性绑定和事件绑定。属性绑定用来向下级(子或孙组件)传递数据,事件绑定用来接收下级(孙组件)发送过来的数据

          2. 在子级组件下面通过porps ,来接收父级组件传递过来的数据。 通过v-bind="$attrs" v-on="$listeners" 向孙级组件传递数据。通过事件绑定来接收孙级组件发送过来的数据。

          3. 在孙级组件通过porps 接收父级组件传递过来的数据。定义点击事件,通过 this.$emit('事件名称',要发送的数据) 向上级(子级或父级)发送数据。

//父组件

<template>
        <div id="App">

            <h2>父级组件:({{name}},{{age}}</h2>
        <child
            :fatherName="name"
            :fatherAge="age"
            @toGrandFather="grandChildValue" 
            @toFather="grandChildValue">
        </child>
    </div>
</template>
<script>
import child from "./Child"
export default {
    name: "App",
    components:{child},
    data(){
            return {
                  name: "小辛",
                  age: 27
            }
    },
    methods:{
        grandChildValue(value){
                console.log("孙组件对我说:"+value)
        }
    }
}
</script>


//子组件child

<template>
    <div id="Child">
        <h2>我是子组件</h2>
        <p>我的父组件名叫{{fatherName}}</p>
        <grandson v-bind="$attrs" v-on="$listeners" @toFather="childValue"></grandson>
    </div>
</template>
<script>
import grandson from "./Grandson"
export default {
    name: "Child",
    components: {grandson},
    // 1.默认true,也就是说当前组件如果没有在props中声明的剩余属性会继承到原始html元素的属性值上。2.改为false,在当前组件中props中没有声明的多余属性不会继承到原始html元素的属性
    inheritAttrs: false,
    // 定义:当前组件已接收的属性指的是当前组件在props中声明的属性
    props: ["fatherName"],
    methods: {
        childValue(value){
                  console.log("子组件对我说:"+value)
        }
    }
}
</script>

//孙组件grandson

<template>
    <div id="grandson">
        <h2>我是孙组件</h2>
        <p>我父组件定义的name名叫{{fatherName}},今年{{fatherAge}}岁</p>
        <button @click="toGrandFather">叫爷爷</button>
        <button @click="toFather">叫爸爸</button>
    </div>
</template>
<script>
export default {
    name: "Grandson",
    props: ["fatherAge","fatherName"],
    methods: {
         toGrandFather(){
                this.$emit("toGrandFather","App.vue,我是您孙组件")
        },
         toFather(){
            this.$emit("toFather","Child.vue,我是您子组件")
        }
    }
}
</script>

 

4.轻量级任何组件间(父子、兄弟、跨级)的通信:

 总结:通过一个空的Vue实例作为$EventBus中央事件总线(事件中心),用它来触发事件和监听事件,巧妙而轻量地实现了任何组件间的通信,包括父子、兄弟、跨级。当我们的项目比较大时,可以选择更好的状态管理解决方案 vuex。EventBus事件不会随着组件的关闭而自行销毁,所以当路由切换时,EventBus事件会不停的触发,如果数据量比较多的时候,可能会比较影响性能吧,所以需要及时销毁所绑定的EventBus事件。在destroyed()生命周期时执行this.$EventBus.$off('事件名称') 进行事件销毁。

通信步骤:

      3.1  首先在main.js将$EventBus绑定在vue实例上。Vue.prototype.$EventBus = new Vue()。在组件出通过this.$EventBus调用。

      3.2  在任意A组件发出数据,this.$EventBus.$emit('事件名','数据');

      3.3  在任意B组件接收数据,this.$EventBus.$on(‘与A组件定义的事件名保持相同',data => {});

//父组件

<template>

     <div id="app">

        <child-a></child-a>

        <child-b></child-b>

        <child-c></child-c>

         <div>

                 <p>{{name }}</p>

                  <p>{{sex}}</p>

                  <p>{{age}}</p>

         <div>

     </div>

</template>

<script>

import child-a from "./components/child-a";

import child-b from "./components/child-b";

import child-c from "./components/child-c";

export default {

     name: 'App',

     components:{

         child-a ,

         child-b,

         child-c

     },   

     data(){

          return {

               name : '',

               sex: '',

               age: ''   

         }

     },     

     mounted(){

           let _this. = this

           _this.fromDataChildB()

           _this.fromDataChildC()

           _this.fromDataChildA()

     },   

    methods:{

              //父组件接收来自任意子组件B的发送的数据

              fromDataChildB(){         

                 let _this. = this

                  _this.$EventBus.$on('sendName', (data)=>{

                        _this.name= data.name

                   })

             },  

            //父组件接收来自任意子组件C的发送的数据

           fromDataChildC(){         

                 let _this. = this

                  _this.$EventBus.$on('sendSex', (data)=>{

                        _this.sex= data.sex

                   })

             },

              //父组件接收来自任意子组件A的发送的数据

             fromDataChildA(){         

                 let _this. = this

                  _this.$EventBus.$on('sendAge', (data)=>{

                        _this.age= data.age

                   })

             }

    },

    destroyed(){

         //事件销毁

         let _this =this

          _this.$EventBus.$off('sendName')

          _this.$EventBus.$off('sendSex')

          _this.$EventBus.$off('sendAge')

    }

}

</script>

//组件child-a

<template>

     <div id="childA">

         <div>{{age}}</div>

        <button  @click="toSendChildB"></button>

     </div>

</template>

<script>

export default {

     name: 'childA',

     data(){

          return {

               age: '',

               name : 'xiaoXin',

         }

     },    

   mounted(){

           let _this. = this

           _this.fromDataChildC()

     },

     methods:{

              //接收来自统计C组件发送的数据

              fromDataChildC(){         

                 let _this. = this

                  _this.$EventBus.$on('sendAge', (data)=>{

                        _this.age= data.age

                   })

             },

              //在任意A组件发出数据,this.$EventBus.$emit('事件名','数据');

              toSendChildB(){

                   let _this. = this

                   _this.$EventBus.$emit('sendName', _this.name)

             }

     },   

    destroyed(){

          let _this =this

          _this.$EventBus.$off('sendAge')

    }

}

</script>

//组件child-b

<template>

     <div id="childB">

        <div>{{name}}</div>

        <button  @click="toSendChildC"></button>

     </div>

</template>

<script>

export default {

     name: 'childB',

     data(){

          return {

               name : '',

               sex: 'man',

         }

     },    

    mounted(){

           let _this. = this

           _this.fromDataChildA()

     },

     methods:{

              //接收来自统计A组件发送的数据

              fromDataChildA(){

                   let _this. = this

                   _this.$EventBus.$on('sendName', (data)=>{

                        _this.name = data.name

                   })

             },

              //在任意B组件发出数据,this.$EventBus.$emit('事件名','数据');

              toSendChildC(){

                   let _this. = this

                   _this.$EventBus.$emit('sendSex', _this.sex)

             }

     },     

    destroyed(){

          let _this = this 

          _this.$EventBus.$off('sendName')

    }

}

</script>

//子组件child-c

<template>

     <div id="childC">

        <div>{{sex}}</div>

        <button  @click="toSendChildA"></button>

     </div>

</template>

<script>

export default {

     name: 'childC',

     data(){

          return {

               sex: '',

               age: '27'

         }

     },    

    mounted(){

           let _this. = this

           _this.fromDataChildB()

     },

     methods:{

              //接收来自统计B组件发送的数据

              fromDataChildB(){

                   let _this. = this

                   _this.$EventBus.$on('sendSex', (data)=>{

                        _this.sex= data.sex

                   })

             },

              //在任意C组件发出数据,this.$EventBus.$emit('事件名','数据');

              toSendChildA(){

                   let _this. = this

                   _this.$EventBus.$emit('sendAge', _this.age)

             }

     },    

   

destroyed(){

          let _this = this 

         _this.$EventBus.$off('sendSex')

    }

}

</script>

5.状态管理器Vuex——万能组件间通信:

总结:Vuex实现了一个单向数据流,在全局拥有一个State存放数据,如果需要对state做计算,可以在getters中进行。当组件要更改State中的数据时,必须通过Mutation进行,Mutation同时提供了订阅者模式供外部插件调用获取State数据的更新。而当所有异步操作(常见于调用后端接口异步获取更新数据)或批量的同步操作需要走Action,但Action也是无法直接修改State的,还是需要通过Mutation来修改State的数据。最后,根据State的变化,渲染到视图上。

通信步骤:

          1.创建store.js 文件,与main.js文件同级。

          2.安装vuex库,在main.js文件里进行引入和注册到vue实例中。

                   安装:npm install --save vuex

                   引入:在store.js 中引入vue和vuex  ,,

                   初始化:在store.js 中 Vue.use(vuex)

                   注册:在main.js 文件引入 store.js ,并注册到vue根实例中    

                 import store from './store/store.js'

           new Vue({

                  el: '#app',

                    store,

                    components: { App },

                    template: '<App/>'

              })

         3. 创建store模块,

              export const store =    new Vuex.Store({  //最重要的事就是保存应用的状态

                  state: {  //状态存储,页面状态管理容器对象

                        num: 0

                  },

                   getters: {

                       doubleNum(state){ //对状态进行计算,state对象读取方法

                            return state.num* 2

                         },

                      },

               mutations: {

                     increment(state){ //state状态改变并做同步提交操做

                       state.num ++

                  },

                  actions: {

                        submitNum({commit}){ //异步提交mutation中的状态,commit是context下的一个方法

                             commit('increment')

                         }

                   }

                 })

         在组件中调用:

                调用原始的状态:this.$store.state.num

                调用gettes计算后的状态:this.$store.gettes.doubleNum

                调用mutations改变后的状态:this.$store.commit('increment')

                调用actions进行异步提交状态:this.$store.dispacth('submitNum')

 Vuex与localStorage的配合:vuex 是 vue 的状态管理器,存储的数据是响应式的。但是并不会保存起来,刷新之后就回到了初始状态。具体做法应该在vuex里数据改变的时候把数据拷贝一份保存到localStorage里面,刷新之后,如果localStorage里有保存的数据,取出来再替换store里的state。由于vuex里,我们保存的状态,都是数组,而localStorage只支持字符串,所以需要用JSON转换。我们常用二者的结合做用户登录和用户登出,以及登录状态保留。

vuex最好的用法是模块化Module,将不同的的状态单独处理。减少彼此的耦合度。

 

本文如果存在错误之处欢迎指出。如有更好的vue.js组件间通信方式感谢指导。感谢观看。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值