到了Vue2.x有哪些变化?—— 组件通信

一、父子组件传递数据

默认情况下父子组件的数据是不共享地

推荐一个Vue辅助工具 —— vue-devtool下载ps:具体查看请参照vue-devtools安装

1. 子组件获取父组件数据(儿子获取父亲数据)

通过选项对象中的props,也就是下面的数据传输过程:


知识点(关于props):

  //方式一:用数组的方式
  props:['m','myMsg']
  //方式二:用json的形式,也就是给数据定义一个数据类型
  props:{
     m': String,
    'myMsg': Number
  }

之前在Vue1.x中,子组件可以更改父组件信息(数据),可以是同步的sync(:msg.sync="父组件数据名")。在利用props获取父级数据的时候加上sync

//注意这个是Vue1.x版本
<body>
    <template id="child">
        <div>
            <h3>我是子组件</h3>
            <input type="button" value="点我" @click="change" />
            <strong>{{ msg }}</strong>
        </div>
    </template>
    <div id="app">
        父级:{{ a }}
        <child-com :msg.sync="a"></child-com>   <!-- 只需要这里设置同步 -->
    </div>
</body>
<script src="vue1.0.js"></script>
<script type="text/javascript">
    var vm = new Vue({
        el: '#app',
        data: {
            a:'我是父组件内的数据'
        },
        components: {
            'child-com': {
                props:['msg'],
                template:'#child',
                methods:{
                    change() {
                        this.msg = '点击我更改数据了'
                    }
                }
            }
        }
    });
</script>

现在Vue2.x,子组件不能直接给父组件数据直接赋值操作(也就是直接修改数据),因为当项目大的时候一个子组件数据更改会引发一系列问题就很麻烦。

但是我们在项目中往往会需要某个子组件更改父组件内数据。这里请看下面

** 父组件每次传一个对象给子组件,利用元素js中对象是引用的(在内存中共用一块地址)**

<body>
    <template id="child">
        <div>
            <h3>我是子组件</h3>
            <input type="button" value="点我" @click="change" />
            <strong>{{ msg.a }}</strong>
        </div>
    </template>
    <div id="app">
        父级:{{ giveData.a }}
        <child-com :msg="giveData"></child-com> <!-- 这里把父组件的json数据传给子组件 -->
    </div>
</body>
<script src="vue.js"></script>
<script type="text/javascript">
    var vm = new Vue({
        el: '#app',
        data: {
            giveData: {
                a:'我是父组件内的数据'
            }
        },
        components: {
            'child-com': {
                props:['msg'],
                template:'#child',
                methods:{
                    change() {
                        this.msg.a = '点击我更改数据了';//这里更改子组件的某一项数据,父组件就跟着改了
                    }
                }
            }
        }
    });
</script>

如图当点击按钮更新子组件数据后:


2. 父组件获取子组件数据(父亲获取儿子数据)

原理:*子组件主动把自己的数据通过$emit(),发送到父级,父组件的模板中有个“事件”,父组件接收的时候用的是“@”(是自定义事件,若有子级数据发送就会触发)

子级:vm.$emit(事件名,数据);
父级: v-on:xxx="xxx" <===> @xxx="xxx"

Ex代码:
<body>
    <div id="box">
        <com-a></com-a>
    </div>
    <template id="testA">
        <div>
            <span>我是父级 => {{msg}}</span>
            <com-b @child-msg="get"></com-b> <!-- 这个首先就是子组件的展示区,其次在挂载自定义事件,当子组件有数据发送的时候就会触发 -->
        </div>
    </template>
    <template id="testB">
        <div>
            <span>子组件</span><input type="button" value="发送数据" @click="send" />
        </div>
    </template>
<script src="vue.js"></script>
<script>
    var comA = {
        data() {
            return {
                msg:'',
            }
        },
        template:'#testA',
        methods:{
            get(data){ //这里面接收到的参数就是子组件发送的数据
                alert(data);
                this.msg = data;
            }
        },
        components:{
            'comB': {
                data(){
                    return {
                        b:'我是子组件的数据'
                    }
                },
                template:'#testB',
                methods:{
                    send(){
                        this.$emit('child-msg',this.b); //这里就是把子组件的b数据通过$emit()方法发送出去
                    }
                }
            }
        }
    }
    var vm=new Vue({
        el:'#box',
        components:{
            comA  //这里等价于 <==> 'comA':comA
        }
    });
</script>

点击子组件发送数据按钮后如下:


3. 兄弟组件之间获取数据(兄弟之间)

首先准备一个var Event = new Vue();,用Event身上的方法
其次在需要发送数据的组件上:Event.$emit(事件名称,数据)
再次在需要接收数据的组件上:
Event.$on(事件名称,function(data){ //data }.bind(this))

Ex代码:把组件A和组件B的数据传到组件C上
<body>
    <div id="app">
       <com-a></com-a>
       <com-b></com-b>
       <com-c></com-c>
    </div>
</body>
<script src="vue.js"></script>
<script type="text/javascript">
    //准备一个空的实例对象,就要它身上的方法
    var Event = new Vue();//全局的
    var A = {
        template: `
            <div>
                <span>我是A组件 => {{ a }}</span>
                <input type="button" value="A数据传给C" @click="send" />
            </div>
        `,
        data() {
            return{
                a:'我是a数据'
            }
        },
        methods:{
            send(){
                Event.$emit('a-msg',this.a);
            }
        }
    }
    var B = {
        template: `
            <div>
                <span>我是B组件 => {{ b }}</span>
                <input type="button" value="B数据传给C" @click="send" />
            </div>
        `,
        data() {
            return{
                b:'我是b数据'
            }
        },
        methods:{
            send(){
                Event.$emit('b-msg',this.b);
            }
        }
    }
    var C = {
        template:`
            <div>
                <h3>我是C组件</h3>
                <span>接收过来的A的数据 => {{ a }}</span>
                <br />
                <span>接收过来的B的数据 => {{ b }}</span>
            </div>
        `,
        data() {
          return{
              a:'',
              b:''
          }
        },
        mounted() {
            alert('C组件加载完毕');
            //var _this = this;
            //接收a组件的数据
            Event.$on('a-msg',function (a) {
                alert(a);//拿到a数据
                this.a = a;
            }.bind(this));//需要绑定给函数
            var _this = this;
            //接收b组件的数据
            Event.$on('b-msg',function (b) {
                alert(b);//拿到b数据
                _this.b = b;
            });
        }
    }
    var vm = new Vue({
        el: '#app',
        components: {
            'com-a':A,
            'com-b':B,
            'com-c':C
        }
    });
</script>

当点击传输A数据给C和传输B数据给C结果如下:


预告——下面将会说Vue2.x中动画(transition)的那些变化。。。

推荐阅读更多精彩内容