Vue组件通信的7个方法

475 阅读2分钟
1.props和$emit

父组件向子组件传递数据是通过prop传递的,子组件传递数据给父组件是通过$emit触发事件来做到的

  Vue.component( "child", { 
                    data () { return {  mymessage:this.message  }  },
                    template:`<div><input type="text" v-model="mymessage" @input="setFather(mymessage)"></div> `,
                    props:{message:String},
                    methods:{setFather (val){this.$emit("getChildData",val) }  }})   
  Vue.component("parent",{ 
                     data:function () { 
                        return {messageFather:"儿子,我是你爸爸啊"} },   
                       template:` <div>  <p> this is parentcomponent!</p><child :message="messageFather" @getChildData="getChildData"></child>  </div> `,   
                       methods:{ getChildData(val){ console.log(val) } } }) 
                       var app = new  Vue({   el:"#app",    })

2.$attrs和$listeners

第一种方式处理父子组件之间的数据传输有一个问题:如果父组件A下面有子组件B,组件B下面有组件C,这时如果组件A想传递数据给组件C怎么办呢? 如果采用第一种方法,我们必须让组件A通过prop传递消息给组件B,组件B在通过prop传递消息给组件C;要是组件A和组件C之间有更多的组件,那采用这种方式就很复杂了。Vue 2.4开始提供了$attrs和$listeners来解决这个问题,能够让组件A之间传递消息给组件C

  <script>    Vue.component("childs",{      data() {        return{          mymessages:"我可能要接受到来自我爷爷的消息"        }      },      template:`        <div>          <p>我是儿子的儿子</p>          <input type="text" v-model="$attrs.messageChilds" @input="getGrandChild($attrs.messageChilds)">          </div>      `,      methods:{        getGrandChild(val){          this.$emit("getGrandChild",val)        }      }    })    Vue.component("child",{      data () {        return {          mymessage:this.message        }      },      template:`        <div>            <input type="text" v-model="mymessage" @input="setFather(mymessage)">              <childs  v-bind="$attrs" v-on="$listeners"></childs>        </div>      `,      props:{        message:String      },      methods:{        setFather (val){          this.$emit("getChildData",val)        }      }    })    Vue.component("parent",{      data:function () {        return {          messageFather:"儿子,我是你爸爸啊",          messageGrandFather:"孙子我是你爸爸啊"        }      },      template:`        <div>          <p> this is parentcomponent!</p>          <child  :messageChilds="messageGrandFather" :message="messageFather" @getChildData="getChildData" @getGrandChild="getGrandChild"></child>        </div>      `,      methods:{        getChildData(val){          console.log(val)        },        getGrandChild(val){          console.log(val)        }      }    })    var app = new  Vue({      el:"#app",    })  </script>

<script> 
   Vue.component("childs",{      
     data() { return{ mymessages:"我可能要接受到来自我爷爷的消息"  } },     
    template:`  <div> <p>我是儿子的儿子</p> <input type="text" v-model="$attrs.messageChilds" @input="getGrandChild($attrs.messageChilds)"> </div>  `,    
      methods:{  getGrandChild(val){ this.$emit("getGrandChild",val)} } }) 
   Vue.component("child",{  
     data () {
        return {
           mymessage:this.message  
           }    
        },    
           
      template:` <div> <input type="text" v-model="mymessage" @input="setFather(mymessage)">  <childs  v-bind="$attrs" v-on="$listeners"></childs> </div>    `,     
       props:{ message:String  },     
       methods:{ setFather (val){this.$emit("getChildData",val) }  } })  
       Vue.component("parent",{ 
         data:function () {  
          return {  
             messageFather:"儿子,我是你爸爸啊", 
             messageGrandFather:"孙子我是你爸爸啊"  
               }      },      
          template:` <div> 
                     <p> this is parentcomponent!</p>
                      <child  :messageChilds="messageGrandFather" :message="messageFather" @getChildData="getChildData" @getGrandChild="getGrandChild">
                      </child>        </div>      `,      
          methods:{   
            getChildData(val){ 
              console.log(val)   
               },       
             getGrandChild(val){ 
               console.log(val)     
              }   
               
             }   
               
            })  
         var app = new  Vue({      el:"#app",    })  </script>

此方法是通过想目标的子组件 绑定 v-bind="$attrs"  与 v-listeners; 而子组件过的数据为$.attrs的对象,数据为 $attrs.messageChild,实现数据的接受,而子组件传递给父组件则是通过$meit传递事件来向父组件传递相应的数据.

3. 中央事件总线

上面两种方式处理的都是父子组件之间的数据传递,而如果两个组件不是父子关系呢?这种情况下可以使用中央事件总线的方式。新建一个Vue事件bus对象,然后通过bus.$emit触发事件,bus.$on监听触发的事件。

  <script>    Vue.component("brotherb",{      data () {        return {          mymessageBrotherB:"我是brotherb",          brothera:''        }      },      template:`        <div>          <p>{{mymessageBrotherB}}</p>          <p>{{brothera}}</p>        </div>      `,      props:{        message:String,            },      mounted(){        bus.$on('globalEvent',(val)=>{         this.brothera=val       })      }    })    Vue.component("brothera",{      data:function () {        return {          messageBrotherA:"我是brotherA",          mymessage:"你好 ,brotherB"        }      },      template:`        <div>          <p>{{messageBrotherA}}</p>           <input type="text" v-model="mymessage" @input="passData(mymessage)">        </div>      `,      methods:{        passData(val){          bus.$emit("globalEvent",val)        }      }    })    //中央事件总线    const bus=new Vue();    const app = new Vue({      el:"#app",    })  </script>

首先我们或创建一个 bus实例, 父组件在mthods方法中,通过bus.$emit()中传递事事件携带参数,然后兄弟组件mounted钩子函数中 通过bus.$on()接受事件和方法.

4. provide和inject

父组件中通过provider来提供变量,然后在子组件中通过inject来注入变量。不论子组件有多深,只要调用了inject那么就可以注入provider中的数据。而不是局限于只能从当前父组件的prop属性来获取数据,只要在父组件的生命周期内,子组件都可以调用。

<script>    Vue.component("child",{      inject:['for'],      data () {        return {          mymessage:"我是儿子",          messageFather:this.for        }      },      template:`        <div>          <p>{{mymessage}}</p>          {{messageFather}}        </div>      `,      mounted(){      }    })    Vue.component("parent",{      data:function () {        return {          mymessage:"我是父亲"        }      },      provide:{        for:"你好儿子啊"      },      template:`        <div>          <p>{{mymessage}}</p>           <child></child>        </div>      `,      methods:{             }    })    const app = new Vue({      el:"#app",    })  </script>

5. v-model

父组件通过v-model传递值给子组件时,会自动传递一个value的prop属性,在子组件中通过this.$emit(‘input',val)自动修改v-model绑定的值

  Vue.component("child",{      props:{        value:String      },      data () {        return {          mymessage:this.value,        }      },      template:`        <div>          <input  type="text" v-model="mymessage" @change="changeValue">        </div>      `,      mounted(){      },      methods:{        changeValue() {          this.$emit('input',this.mymessage)        }      }    })    Vue.component("parent",{      data:function () {        return {          message:"son",        }      },      template:`        <div>          <p>{{message}}</p>           <child v-model="message"></child>        </div>      `,      methods:{             }    })    const app = new Vue({      el:"#app",    })  </script>

6. $parent和$children

 <script>    Vue.component("child",{      data () {        return {          mymessage:"我是儿子",        }      },      template:`        <div>         <input type="text" v-model="mymessage" @change="changeParent">        </div>      `,      mounted(){      },      methods:{        changeParent () {          this.$parent.message=this.mymessage        }      }    })    Vue.component("parent",{      data:function () {        return {          message:"我是父亲",        }      },      template:`        <div>          <p>{{message}}</p>           <button @click="changeBtn">改变儿子</button>          <child></child>        </div>      `,      methods:{        changeBtn () {          this.$children[0].mymessage="hello"        }      }    })    const app = new Vue({      el:"#app",    })  </script>

父组件通过methods事件 通过事件 触发 this.$children[1].message="hello"来向子组件中传递值,1为父组件中第一个子组件,

子组件通过this.$parent.message=this.mymessage来修改  父组件中message 的值.

7. vuex处理组件之间的数据交互

如果业务逻辑复杂,很多组件之间需要同时处理一些公共的数据,这个时候才有上面这一些方法可能不利于项目的维护,vuex的做法就是将这一些公共的数据抽离出来,然后其他组件就可以对这个公共数据进行读写操作,这样达到了解耦的目的。