events.js 2.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  1. /* @flow */
  2. import { toArray } from '../util/index'
  3. import { updateListeners } from '../vdom/helpers/index'
  4. export function initEvents (vm: Component) {
  5. vm._events = Object.create(null)
  6. // init parent attached events
  7. const listeners = vm.$options._parentListeners
  8. if (listeners) {
  9. updateComponentListeners(vm, listeners)
  10. }
  11. }
  12. let target: Component
  13. function add (event, fn, once) {
  14. if (once) {
  15. target.$once(event, fn)
  16. } else {
  17. target.$on(event, fn)
  18. }
  19. }
  20. function remove (event, fn) {
  21. target.$off(event, fn)
  22. }
  23. export function updateComponentListeners (
  24. vm: Component,
  25. listeners: Object,
  26. oldListeners: ?Object
  27. ) {
  28. target = vm
  29. updateListeners(listeners, oldListeners || {}, add, remove, vm)
  30. }
  31. export function eventsMixin (Vue: Class<Component>) {
  32. Vue.prototype.$on = function (event: string, fn: Function): Component {
  33. const vm: Component = this
  34. ;(vm._events[event] || (vm._events[event] = [])).push(fn)
  35. return vm
  36. }
  37. Vue.prototype.$once = function (event: string, fn: Function): Component {
  38. const vm: Component = this
  39. function on () {
  40. vm.$off(event, on)
  41. fn.apply(vm, arguments)
  42. }
  43. on.fn = fn
  44. vm.$on(event, on)
  45. return vm
  46. }
  47. Vue.prototype.$off = function (event?: string, fn?: Function): Component {
  48. const vm: Component = this
  49. // all
  50. if (!arguments.length) {
  51. vm._events = Object.create(null)
  52. return vm
  53. }
  54. // specific event
  55. const cbs = vm._events[event]
  56. if (!cbs) {
  57. return vm
  58. }
  59. if (arguments.length === 1) {
  60. vm._events[event] = null
  61. return vm
  62. }
  63. // specific handler
  64. let cb
  65. let i = cbs.length
  66. while (i--) {
  67. cb = cbs[i]
  68. if (cb === fn || cb.fn === fn) {
  69. cbs.splice(i, 1)
  70. break
  71. }
  72. }
  73. return vm
  74. }
  75. Vue.prototype.$emit = function (event: string): Component {
  76. const vm: Component = this
  77. let cbs = vm._events[event]
  78. if (cbs) {
  79. cbs = cbs.length > 1 ? toArray(cbs) : cbs
  80. const args = toArray(arguments, 1)
  81. for (let i = 0, l = cbs.length; i < l; i++) {
  82. cbs[i].apply(vm, args)
  83. }
  84. }
  85. return vm
  86. }
  87. }