zoukankan      html  css  js  c++  java
  • vue---组件间通信

    vue中比较重要的就是组件了。而组件随处可复用的特性,使得组件通信非常重要。那么组件之间通讯方式有哪些呢?

    第一种:父子组件通讯:

    如果是 html页面 中全局注册的组件 和 实例中局部注册的组件

    HTML:

    <div id="box"></div>

    JS:

    Vue.component('child',{
        name:'child',
        props:{
            msg:{
                type:String,
                require:true
            }
        },
        template:`
            <div id='getChild'>
                <h3>我是child组件</h3>
                <p>{{msg}}</p>
                <button @click='getParentVal'>点击获取父组件内容</button>
                <button @click='sendVal'>向父组件传递内容</button>
            </div>
        `,
        data:function(){
            return {
                childVal:'我是子组件中的数据'
            }
        },
        methods:{
            //这里是获取父组件中的属性或方法
            getParentVal:function(){
                console.log(this.$parent.age)
            },
            //这个是向父组件传递指定的内容
            sendVal:function(){
                this.$emit('sendChild',{
                    mssg:'我是子组件$emit传过来的内容'
                })
            }
        }
    })
    Vue.component('myParent',{
        name:'parent',
        template:`
            <div>
                <button @click='getVal'>点我获取子组件内容</button>
                <child :msg='parentVal' ref='getChild' @sendChild='getSendChild'></child>    
            </div>
        `,
        data:function(){
            return {
                parentVal:'我是parent组件传过来的值',
                age:666
            }
        },
        methods:{
            //这个是获取子组件的属性或方法
            getVal:function(){
                console.log(this.$refs.getChild.childVal)
            },
            //这个是获取子组件通过emit传递过来的内容
            getSendChild:function(res){
                console.log(res)
            }
        }
    })
    
    new Vue({
        el:'#box',
      //这里局部注册父组件
      template:`
        <my-parent></my-parent>
      `
    })

    注意事项:

    1) 组件需要先注册才能使用,注册又分 局部注册 和 全局注册。局部注册需要在实例里面的template声明组件的内容,全局注册即如上例一样。

    2) 组件名支持驼峰小写大写,横线(xxx-xxx)的写法。但是在使用组件的时候,如果是驼峰的写法,则需要写成横线的形式。如上面 组件名是myParent ,那么使用的时候 就必须是 <my-parent></my-parent> 。

    3) 父组件可以获取子组件的数据和方法,通过在引用子组件的时候定义 ref='自定义名称'  ,然后在子组件的template中最外层节点定义一个id值,然后父组件中使用  this.$refs.自定名称.子组件数据  。就如同上例点击获取子组件数据一样。或者不加ref,直接使用 this.$children[第几个子组件].子组件数据

    4) 子组件可以获取父组件的数据和方法,在子组件中使用 this.$parent.子组件数据。

    5) 子组件通过 $emit('自定义名称',数据) 来达到向父组件传递指定的数据,类似 jQuery 的 trigger 。

    6) 父组件通过 实例.$on('对应emit定义的名称',function(res){}) 或者  在引用子组件的时候   <child @对应emit定义的名称='自己定义的函数名'></child> ,然后在methods中指定  自己定义的函数名  获取到的  res 就是子组件传过来的值。

    7) template 里面的内容 可以用  ` `  就是键盘上 esc 下面的那个波浪键 在英文状态下打出来的内容  ,这样就不用向es5一样用 + 加号和 ' ' 引号来合并成字符串了。

    8) props 中命名方式 不支持 xxx-xxx 这种横线的格式支持驼峰,小写。如果props中是驼峰的命名方式,那引用组件的时候就要写成对应的横线方式,例如props:[getPhone]   那么<child get-phone='xxx'></child> ,如果绑定的是动态值也是一样的写法<child :get-phone='xxx'></child>  。原因:由于html不区分大小写的特性,所以没法对应组件中的驼峰名称。

    9) 为什么组件中的data必须是函数,然后返回对象?因为组件是用于复用的,彼此之间的数据一定要是唯一的。所以如果data就是一个对象,那么由于对象是引用类型,不同地方引用同一个对象,并不是引用的值,而是引用的对象的地址,所以某一处修改之后,其它的也会跟着变化,这样就不能达到数据唯一的目的。而使用函数再返回一个对象,每个对象的地址都是不同的,就能保证每次都是一个新的对象。

    10)props验证方式的写法可以查看官网,里面的prop验证

    11) template 里面的内容必须只有一个根元素。

    如果是 .vue 这种单文件模块 的组件

    这种方式和 html 页面 中注册组件有稍许的不一样。

    //child 组件
    <template>
        <div>
            xxxx
        </div>
    </template>
    <script>
        export default {
            props:[],
            data:function(){}
        }
    </script>
    <style>
    
    </style>   

      

    //parent 组件
    <template>
        <div>
            <childComponent></childComponent>
            //如果注册的时候不重命名的话就可以使用<child></child>
        </div>
    </template>
    <script>
        import child from 'xxx'
        export default {
            data:function(){},   
            components:{
                'childComponent':child  //如果不重名的话可以直接是{child}
            },
            data:function(){}
        }
    </script>
    <style>
    
    </style> 

     说明:

    1) 每个 .vue单文件组件模块,都需要在 template 中声明组件的内容,并且也只有一个根元素

    2) 在script 里面 需要 export default 组件注册的必须内容,例如props,data,mthods等。

    3) 在需要引入组件的页面  import  自定义组件名称  from  'xxx' 。组件的名称自定义,支持大写,小写,驼峰,横线(xxx-xxx)

    4) import 组件之后,还需要在components中注册组件。注册的时候也可以重命名组件名称。

    5) 除了上面的区别,其它的就没什么区别了,组件的通讯也和上面 html页面中组件通讯一样的处理方式。

    第二种:非父子组件之间的通讯。

    在 html 页面中,注册方式与父子组件无差别,也是全局注册和局部注册。

    HTML:

    <div id="box"></div>

    JS:

    //全局注册mine组件
    Vue.component('mine',{
        template:`
            <div>
                我是mine组件
                <button @click='sendToBrother'>点击向brother组件发送内容</button>
            </div>
        `,
        data:function(){
            return {
                name:'mine',
                sex:'male'
            }
        },
        mounted:function(){
            //接收mine组件传过来的内容
            transfer.$on('brotherVal',function(res){
                console.log(res)
            })
        },
        methods:{
            //向brother组件传递内容
            sendToBrother:function(){
                transfer.$emit('mineVal',this.name)
            }
        }
    })
    //全局注册brother组件   
    Vue.component('brother',{
        template:`
            <div>
                我是brother组件
                <button @click='sendToMine'>点击向mine组件发送内容</button>
            </div>
        `,
        data:function(){
            return {
                name:'brother',
                age:666
            }
        },
        mounted:function(){
            //接收mine组件传过来的内容
            transfer.$on('mineVal',function(res){
                console.log(res)
            })
        },
        methods:{
            //向mine组件发送内容
            sendToMine:function(){
                transfer.$emit('brotherVal',this.name)
            }
        }
    })
    
    //这是最重要的一步,定一个空的实例对象。
    var transfer=new Vue();
    
    new Vue({
        el:'#box',
        data:{},
        //局部注册两个组件
        template:`
            <div>
              <mine></mine>
              <brother></brother>
            </div>
         `
    })

    说明:

    1) 主要的就是通过一个 中间实例对象来实现 非父子组件之间的通讯

    2) 还是通过 $emit() 来发送内容 , $on() 来接收传递过来的内容 ,只是使用这两个方法的对象并不是 this 而是 一个空的实例对象。要注意 $on 和 $emit 中的事件名要对应

    3) 不一定是mounted的时候才去接收传过来的内容,created的时候也是可以的。应该是只要生命周期里,数据初始化完成之后都行。

    4) 具体是什么原理,我不清楚。也感觉没必要去搞懂

    如果是 .vue 这种单文件模块 的组件

    这种方式和 html 页面 中注册组件有稍许的不一样。而且通讯的方式也有一点差距。

    第一步:需要中间实例对象,于是新建一个  transfer.js

    import Vue from 'vue'
    export default new Vue();

    第二步:需要传值的页面,引入这个js

    //mine 组件
    <template>
        <div>
            <button @click='sendToBrother'>点我向brother组件发送内容</button>
        </div>
    </template>
    <script>
        import transfer from 'transfer.js的路径'
        export default {
            data:function(){
               return {}  
            },
            methods:{
                sendToBrother:function(){
                    transfer.$emit('sendVal','这是mine组件传过来的值')
                }    
            }
        }
    </script>
    <style>
    
    </style>          
    //brother 组件
    <template>
        <div>
            xxx
        </div>
    </template>
    <script>
        import transfer from 'transfer.js的路径'
        export default {
            data:function(){
               return {}  
            },
            mounted:function(){
                transfer.$on('sendVal',function(res){
                    console.log(res)
                })
            }
        }
    </script>
    <style>
    
    </style>          

    第三步:在引用这两个组件的地方,注册这两个组件。

    //引入组件的页面
    <template>
        <div>
            <mine></mine>
            <brother></brother>
        </div>
    </template>
    <script>
        import mine from 'mine组件的路径';
        import brother from 'brother组件的路径'
        export default {
            data:function(){
               return {}  
            },
            components:{ mine ,brother },
        }
    </script>
    <style>
    
    </style>        

    说明:

    1) 实现的方式还是差不多的 , 都是 $on 接收内容   $emit 发送内容。

    2) 只是中间实例对象需要添加到一个 js 中。然后两个组件页面都需要引入

    3) 这种通过中间实例对象的方式,也可以用于  父子、祖孙 等关系的组件通讯。

    上面的通讯方式是最常见的。但是在组件通讯这块,vue 2.4 版本又增加了 inheritAttrs、attrs和listeners 。这三个的用法,后面再找个机会补上。


    如果遇到 父级组件需要传给 子级组件的props值 是通过  ajax  异步请求  传入的  。那么,在子组件的生命周期中获取该props内容是获取不了的。就算是在mounted 中也是获取不了的。

    这个时候的解决办法是:

    <childComponent  :sendVal='getval'  v-if='getval'></childComponent>

    一定要加一个  v-if ,这样才能在 子组件的 mounted 中获取到该值。这个地方是把我坑惨的。。。网上有推荐说如果是数组,可以使用  v-if = 'getval.length' 。这完全没必要,而且有可能还会报错,因为getval的值有可能还没返回来,再去取length肯定会报错。 如果是布尔值的话,更要注意点。

  • 相关阅读:
    c语言-何为编程?
    c语言-注释
    【转】使用DirectUI技术实现QQ界面
    c语言-error C2440: “static_cast”: 无法从“UINT (__thiscall CHyperLink::* )(CPoint)”转换为“LRESULT (__thiscall CWnd::* )(CPoint)”
    系统分析师【转】
    c语言-经验之谈
    开源托管站点大全
    c语言-扑克牌小魔术
    c语言-猜数字游戏
    世界语简介
  • 原文地址:https://www.cnblogs.com/zjjDaily/p/10511728.html
Copyright © 2011-2022 走看看