Source: internal/events.js

/**
 * Created by zhangmike on 16/10/17.
 */
let delegateEventSplitter = /^(\S+)\s*(.*)$/;
export default function eventsMixin(GMP) {
    /**
     * Setup the instance's option events.
     * If the value is a string, we pull it from the
     * instance's methods by name.
     */
    GMP.prototype._initEvents = function() {
        registerCallbacks(this, this.events);
    };
    GMP.prototype.undelegateEvents = function() {
        if (this.$el) this.$el.off('.delegateEvents' + this._uid);
        return this;
    };
    GMP.prototype.delegateEvents = function(events) {
        events || (events = _.result(this, 'events'));
        if (!events) return this;
        this.undelegateEvents();
        for (var key in events) {
            var method = events[key];
            if (!_.isFunction(method)) method = this.methods[method];
            if (!method) {
                continue;
            }
            var match = key.match(delegateEventSplitter);
            this.delegate(match[1], match[2], _.bind(method, this));
        }
        return this;
    };

    GMP.prototype.delegate = function(eventName, selector, listener) {
        this.$el.on(eventName + '.delegateEvents' + this._uid, selector, listener);
        return this;
    };

    GMP.prototype._setElement = function(el) {
        this.$el = el instanceof GMP.$ ? el : GMP.$(el);
        this.el = this.$el[0];
    };

    GMP.prototype._callHook = function(hook) {
        console.log(this);
        var handlers = this.$options[hook];
        if (hook) {
            handlers.call(this);
        }
    };
};

function registerCallbacks(vm, events) {
    if (!events) return;
    vm.undelegateEvents();
    vm._setElement(_.result(vm, 'el'));
    vm.delegateEvents(events);
    return vm;
};