美文网首页前端开发那些事儿
vue高级进阶( 二 ) 8种组件通信详解

vue高级进阶( 二 ) 8种组件通信详解

作者: 一人创客 | 来源:发表于2021-02-20 18:05 被阅读0次

    猛兽总是独行,牛羊才成群结队。 -------鲁迅

    vue组件通信的重要性无需多言。。。但是你肯定没有全部掌握,所以这第二篇文章应运而生

    props和$emit

    props父传子,$emit子传父,看下边代码,清澈的像少女的眼眸。。。emmm

        Vue.component('child',{
            data(){
                return {
                    mymessage:this.message
                }
            },
            template:`
                <div>
                    <input type="text" v-model="mymessage" 
                    @input="passData(mymessage)"> </div>
            `,
            props:['message'],//得到父组件传递过来的数据
            methods:{
                passData(val){
                    //触发父组件中的事件
                    this.$emit('getChildData',val)
                }
            }
        })
    ┄┅┄┅┄┅┄┄┅┄┅┄┅┄┄┅┄┅┄┅┄┄┅┄┅┄┅┄┄┅┄┅┄┅┄┄┅┄┅┄┅┄┄┅┄┅┄┅┄┅┄*
        Vue.component('parent',{
            template:`
                <div>
                    <p>this is parent compoent!</p>
                    <child :message="message"
                    v-on:getChildData="getChildData"></child>
                </div>
            `,
            data(){
                return {
                    message:'张不怂'
                }
            },
            methods:{
                //执行子组件触发的事件
                getChildData(val){
                    console.log(val)
                }
            }
        })
    ┄┅┄┅┄┅┄┄┅┄┅┄┅┄┄┅┄┅┄┅┄┄┅┄┅┄┅┄┄┅┄┅┄┅┄┄┅┄┅┄┅┄┄┅┄┅┄┅┄┅┄*
    
         // 挂载
        var app=new Vue({
            el:'#app',
            template:`
                <div>
                    <parent></parent>
                </div>
            `
        })
    复制代码
    

    中央事件总线new Bus

    新建一个Vue事件bus对象,然后通过bus.$emit触发事件,bus.$on监听触发的事件。

    Vue.component('brother1',{
            data(){
                return {
                    mymessage:'hello brother1'
                }
            },
            template:`
                <div>
                    <p>this is brother1 compoent!</p>
                    <input type="text" v-model="mymessage"
                    @input="passData(mymessage)"> 
    
                </div>
            `,
            methods:{
                passData(val){
                    //触发全局事件globalEvent
                    bus.$emit('globalEvent',val)
    
                }
            }
        })
     ┄┅┄┅┄┅┄┄┅┄┅┄┅┄┄┅┄┅┄┅┄┄┅┄┅┄┅┄┄┅┄┅┄┅┄┄┅┄┅┄┅┄┄┅┄┅┄┅┄┅┄*
    
        Vue.component('brother2',{
            template:`
                <div>
                    <p>this is brother2 compoent!</p>
                    <p>brother1传递过来的数据:{{brothermessage}}</p>
                </div>
            `,
            data(){
                return {
                    mymessage:'hello brother2',
    
                    brothermessage:''
                }
            },
            mounted(){
                //绑定全局事件globalEvent
                bus.$on('globalEvent',(val)=>{
                    this.brothermessage=val;
                })
            }
        })
    ┄┅┄┅┄┅┄┄┅┄┅┄┅┄┄┅┄┅┄┅┄┄┅┄┅┄┅┄┄┅┄┅┄┅┄┄┅┄┅┄┅┄┄┅┄┅┄┅┄┅┄*
    
        //中央事件总线
        var bus=new Vue();
    
        var app=new Vue({
            el:'#app',
            template:`
                <div>
                    <brother1></brother1>
                    <brother2></brother2>
                </div>
            `
        })
    复制代码
    

    provide和inject

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

    Vue.component('child',{
            inject:['parent_var'],//得到父组件传递过来的数据
            data(){
                return {
                    mymessage:this.parent_var
                }
            },
            template:`
                <div>
                   {{ message }}
                </div>
        })
    ┄┅┄┅┄┅┄┄┅┄┅┄┅┄┄┅┄┅┄┅┄┄┅┄┅┄┅┄┄┅┄┅┄┅┄┄┅┄┅┄┅┄┄┅┄┅┄┅┄┅┄*
        Vue.component('parent',{
            template:`
                <div>
                    <child></child>
                </div>
            `,
            provide:{
                // 看你想传递啥了,这里不写固定的原因是为了防止限制大家的思维
                /*
                比如你可以把用户登录信息存储在App.vue中,可以把
                provide:{app:this}注入,后续所有组件通过inject:['app'],
                就可以直接通过app.userInfo拿到用户信息
                */
                parent_var:'随便什么都可以(可以是this,可以是data中的数据)'
            },
            data(){
                return {
                    message:'hello'
                }
            }
        })
    ┄┅┄┅┄┅┄┄┅┄┅┄┅┄┄┅┄┅┄┅┄┄┅┄┅┄┅┄┄┅┄┅┄┅┄┄┅┄┅┄┅┄┄┅┄┅┄┅┄┅┄*
        var app=new Vue({
            el:'#app',
            template:`
                <div>
                    <parent></parent>
                </div>
            `
        })
    复制代码
    

    $attrs和$listeners

    还是多层的场景,App.vue-->A—>B,如果App直接想给B传递数据该怎么办?Vue 2.4开始提供了[图片上传失败...(image-17bd97-1613815451793)]

    listeners来解决这个问题,能够让组件App直接传递数据给组件B。我将代码中关键点已经标注出, // ******关键点*****

    app.vue引入A组件

    <template>
      <div id="app">
        {{app}}
        // ******关键点*****
        <A :app="app" @test="doTest"/>
      </div>
    </template>
    
    <script>
    import A from "./components/A";
    
    export default {
      name: "App",
      data() {
        return {
          app: "我是App的数据"
        };
      },
      components: {
        A
      },
      methods: {
        doTest() {
          console.log(this.app)
        }
      }
    };
    复制代码
    

    A.vue引入B组件

    <template>
      <div class="hello">
        <h6>这里是A组件</h6>
        <p>$attrs: {{$attrs}}</p>
        <p>$listeners: {{$listeners}}</p>
         // ******关键点***** v-bind传递的都是$attrs,v-on传递的都是$listeners
        <B v-bind="$attrs" v-on="$listeners"/>
      </div>
    </template>
    
    <script>
    import B from "./B";
    
    export default {
      name: "A",
      props: {
        msg: String
      },
      components: { B },
      mounted() {
        console.log(this.$listeners);
      }
    };
    </script>
    复制代码
    

    B组件

    <template>
      <div class="hello">
        <h6>这里是B组件</h6>
         // ******关键点*****
        <p>$attrs: {{$attrs}}</p>
      </div>
    </template>
    
    <script>
    
    export default {
      name: "B",
      props: {
        msg: String
      },
      mounted() {
       // ******关键点*****
       // 为啥这里直接能emitApp组件传递的test呢?
       // 因为在A组件中有一个关键操作是  <B v-bind="$attrs" v-on="$listeners"/>
        this.$emit("test");
      }
    };
    </script>
    复制代码
    

    $parent和$children

    分别是获得父组件和子组件的实例

    Vue.component('child',{
            props:{
                value:String, //v-model会自动传递一个字段为value的prop属性
            },
            data(){
                return {
                    mymessage:this.value
                }
            },
            methods:{
                changeValue(){
                    this.$parent.message = this.mymessage;//通过如此调用可以改变父组件的值
                }
            },
            template:`
                <div>
                    <input type="text" v-model="mymessage" @change="changeValue"> 
                </div>
        })
        Vue.component('parent',{
            template:`
                <div>
                    <p>this is parent compoent!</p>
                    <button @click="changeChildValue">test</button >
                    <child></child>
                </div>
            `,
            methods:{
                changeChildValue(){
                    this.$children[0].mymessage = 'hello';
                }
            },
            data(){
                return {
                    message:'hello'
                }
            }
        })
        var app=new Vue({
            el:'#app',
            template:`
                <div>
                    <parent></parent>
                </div>
            `
        })
    复制代码
    

    v-model

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

    Vue.component('child',{
            props:{
                value:String, //v-model会自动传递一个字段为value的prop属性
            },
            data(){
                return {
                    mymessage:this.value
                }
            },
            methods:{
                changeValue(){
                    this.$emit('input',this.mymessage); //通过如此调用可以改变父组件上v-model绑定的值
                }
            },
            template:`
                <div>
                    <input type="text" v-model="mymessage" @change="changeValue"> 
                </div>
        })
        Vue.component('parent',{
            template:`
                <div>
                    <p>this is parent compoent!</p>
                    <p>{{message}}</p>
                    <child v-model="message"></child>
                </div>
            `,
            data(){
                return {
                    message:'hello'
                }
            }
        })
        var app=new Vue({
            el:'#app',
            template:`
                <div>
                    <parent></parent>
                </div>
            `
        })
    复制代码
    

    boradcast和dispatch

    vue1.0中提供了这种方式,但vue2.0中没有,但很多开源软件都自己封装了这种方式,比如min ui、element ui, broadcast是向特定的父组件,触发事件,dispatch是向特定的子组件触发事件,本质上这种方式还是使用递归对on和emit的封装,但在一些基础组件中却很实用。注意:所有组件的名称不能重复!!!

    function broadcast(componentName, eventName, params) {
      this.$children.forEach(child => {
        var name = child.$options.componentName;
    
        if (name === componentName) {
          child.$emit.apply(child, [eventName].concat(params));
        } else {
          broadcast.apply(child, [componentName, eventName].concat(params));
        }
      });
    }
    
    function dispatch(componentName, eventName, params) {
            var parent = this.$parent;
          var name = parent.$options.componentName;
          while (parent && (!name && name !== componentName)) {
            parent = parent.$parent;
            if (parent) {
              name = parent.$options.componentName;
            }
          }
          if (parent) {
            parent.$emit.apply(parent, [eventName].concat(params));
          }
    }
    export default {
      methods: {
        dispatch(componentName, eventName, params) {
          dispatch.call(this, componentName, eventName, params);
        },
        broadcast(componentName, eventName, params) {
          broadcast.call(this, componentName, eventName, params);
        }
      }
    };
    复制代码
    

    vuex

    对于vuex不再做过多的赘述。。。

    第二章非常全面的讲解了vue炒鸡重要的一个技能,组件通信,我说这一篇全面大家应该没意见吧?好了就这样...

    觉得对你有帮助,不妨点个

    ,后续持续输出这种简短有效的文章,帮助你用最短的时间内掌握最多的内容,毕竟谁不喜欢一劳永逸不是? ❥(^_-) thank you ~

    后续目录

    vue高级进阶( 一 ) 组件精髓概述

    vue高级进阶( 二 ) 8种组件通信详解

    vue高级进阶( 三 ) 组件高级用法及最佳实践

    相关文章

      网友评论

        本文标题:vue高级进阶( 二 ) 8种组件通信详解

        本文链接:https://www.haomeiwen.com/subject/ppjxfltx.html