Special v-on syntax

by Rahul Kadyan

HTML

<script src="https://unpkg.com/vue/dist/vue.js"></script>

<div id="app">
  <test v-on="handleEvents">v-on="handleEvents"</test>
  <test v-on="'handleEvents'">v-on="'handleEvents'"</test>
  <test v-on="[handleEvents, handleEvents2]">v-on="[handleEvents, handleEvents2]"</test>
  <test v-on="['handleEvents', 'handleEvents2']">v-on="['handleEvents', 'handleEvents2']"</test>
  <test v-on="{ action: handleAction }">v-on="{ action: handleAction }"</test>
  <test v-on="{ action: 'handleAction' }">v-on="{ action: 'handleAction' }"</test>
  <test v-on="['handleEvents', { action: 'handleAction' }]">v-on="['handleEvents', { action: 'handleAction' }]"</test>
  <test v-on="handlers">v-on="handlers"</test>
  
  <pre>handlers: {{ handlers | json }}</pre>
  
  <pipe v-on="handleEvents">Pipe</pipe>
</div>

CSS

button {
  background: #40b883;
  color: white;
  font-size: 12px;
  font-family: monospace;
  border: none;
  border-radius: 3px;
  padding: 10px 12px;
  margin: 12px;
  cursor: pointer;
}

button:hover {
  background: #7cd1ab;
}

pre {
  margin: 12px;
}

JavaScript

const SpecialVOn = {
	install (Vue) {
    const superEmit = Vue.prototype.$emit
    Vue.prototype.$emit = function (event, ...args) {
      superEmit.call(this, event, ...args)
      if (this._events.$all) {
        for (let k in this._events.$all) {
          this._events.$all[k].forEach(cb => {
            cb.call(this, event, ...args)
          })
        }
      }
    }

    function removeItem (array, item) {
      const index = array.indexOf(item)
      if (index !== -1) {
        array.splice(index, 1)
      }
    }

    function getMethod (vnode, value) {
      let fn
      if (typeof value === 'function') {
        fn = value
      } else if (typeof value === 'string') {
        fn = vnode.context[value]
      }
      return fn
    }

    function $on (vnode, event, value) {
      const fn = getMethod(vnode, value)
      if (fn) {
        vnode.child.$on(event, fn)
      }
    }

    function $off (vnode, event, value) {
      const fn = getMethod(vnode, value)
      if (fn) {
        vnode.child.$off(event, fn)
      }
    }

    function getCbs (vnode) {
      const vm = vnode.child
      const uid = vnode.context._uid
      const $all = (vm._events.$all || (vm._events.$all = {}))
      const cbs = ($all[uid] || ($all[uid] = []))
      return cbs
    }

    function addCbs (vnode, value) {
      const cbs = getCbs(vnode)
      if (typeof value === 'function' || typeof value === 'string') {
        const fn = getMethod(vnode, value)
        if (fn) {
          cbs.push(fn)
        }
      } else if (Array.isArray(value)) {
        value.forEach(cb => {
          addCbs(vnode, cb)
        })
      } else if (typeof value === 'object') {
        for (let k in value) {
          const currentValue = value[k]
          if (Array.isArray(currentValue)) {
            currentValue.forEach(v => {
              $on(vnode, k, v)
            })
          } else {
            $on(vnode, k, currentValue)
          }
        }
      }
    }

    function removeCbs...