Vue里面子组件是如何通过自定义事件向父组件传值

题目描述

《Vue.js实战》里面的关于组件通信的章节,有一篇关于介绍自定义事件的。子组件的自定义事件通过$emit通知父组件,而父组件可通过v-on监听子组件的自定义事件。虽然知道,是这样的一个机制,但是看到下面的代码之后就还是没理解实质。希望大神能够解释一下,最好形象一些。

题目来源及自己的思路

《Vue.js实战》第7章 7.3节组件通信 7.3.1 自定义事件

<my-component @increase="handleGetTotal" @reduce="handleGetTotal"></my-component>

看到这里我是理解成这样:自定义标签my-component定义了两个自定义事件increase和reduce,这两个事件的事件处理程序都是handleGetTotal,所以我就去了子组件内查这个处理程序,但是发现子组件的methods里面没有,只有handleIncrease和handleReduce,这里感觉困惑。然后想这个是父组件通过v-on监听这两个事件,所以事件处理程序handleGetTotal应该是父组件提供?然后看到确实在父组件的methods里面找到了。所以,虽然increase和reduce是子组件自已定义的事件,但是对应的处理程序(这些事件都干些什么)一定是父组件提供?这个理解对么?

然后再看详细的函数内容:

handleGetTotal: function(total) {
                this.total = total;
                console.log(this);  //Vue
            }

function(total)这里的total看起来似乎是从子组件那边传过来的,似乎是通过

this.$emit('increase', this.counter);
this.$emit('reduce', this.counter);

但是,到底是不是这样传的?如果是这样传的 this.counter 作为子组件的数据怎么和function(total)这里的total对应起来的?我测试function(total)这里的参数是任意字符串都可以,所以对应起来:

@increase="handleGetTotal"
this.$emit('increase', this.counter);


@reduce="handleGetTotal"
this.$emit('reduce', this.counter);

this.counter作为子组件处理之后的数据又回传给父组件提供的函数handleGetTotal。是不是这样的呢?
如果是这样的话,前面的疑问似乎就是解了?

相关代码

// 请把代码文本粘贴到下方(请勿用图片代替代码)

  <div id="app" v-cloak>
        <p>总数:{{total}}</p>
        <my-component @increase="handleGetTotal" @reduce="handleGetTotal"></my-component>
  </div>
    
    <script src="https://unpkg.com/vue/dist/vue.js"></script>
    <script>
    Vue.component('my-component', {
        template: `\
        <div>\
            <button @click="handleIncrease">+1</button>\
            <button @click="handleReduce">-1</button>\
         </div>`,
        data: function() {
            return {
                counter: 0
            }
        },
        methods: {
            handleIncrease: function() {
                this.counter++;
                this.$emit('increase', this.counter);
                console.log(this);  //VueComponent
            },
            handleReduce: function() {
                this.counter--;
                this.$emit('reduce', this.counter);
                console.log(this);   //VueComponent
            },
        }
    })
    var app = new Vue({
        el: '#app',
        data: {
            total: 0
        },
        methods: {
            handleGetTotal: function(total) {
                this.total = total;
                console.log(this);  //Vue
            }
        }
    })
    </script>
阅读 3.9k
1 个回答

首先,事件是绑定在子组件上的,无论是父组件传递,还是子组件内部自行$on。
事件本质上是通过,创建子组件式时以key(increase, reduce), callback(handleGetTotal)传递进去的,这样就绑定了他们的关系。

Vue 每个组件都会维护一个events bus,以下是Vue源码

Vue.prototype.$on = function (event: string, fn: Function): Component {
    const vm: Component = this
    ;(vm._events[event] || (vm._events[event] = [])).push(fn)
    return vm
  }

 Vue.prototype.$emit = function (event: string): Component {
    const vm: Component = this
    let cbs = vm._events[event]
    if (cbs) {
      cbs = cbs.length > 1 ? toArray(cbs) : cbs
      const args = toArray(arguments, 1)
      for (let i = 0, l = cbs.length; i < l; i++) {
        cbs[i].apply(vm, args)
      }
    }
    return vm
  }
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题