directive.js 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. var _ = require('./util')
  2. var Watcher = require('./watcher')
  3. /**
  4. * A directive links a DOM element with a piece of data,
  5. * which is the result of evaluating an expression.
  6. * It registers a watcher with the expression and calls
  7. * the DOM update function when a change is triggered.
  8. *
  9. * @param {String} name
  10. * @param {Node} el
  11. * @param {Vue} vm
  12. * @param {Object} descriptor
  13. * - {String} expression
  14. * - {String} [arg]
  15. * - {Array<Object>} [filters]
  16. * @constructor
  17. */
  18. function Directive (name, el, vm, descriptor) {
  19. // public
  20. this.name = name
  21. this.el = el
  22. this.vm = vm
  23. this.arg = descriptor.arg
  24. this.expression = descriptor.expression
  25. this.filters = descriptor.filters
  26. // private
  27. this._locked = false
  28. this._bound = false
  29. // init definition
  30. this._initDef()
  31. this._bind()
  32. }
  33. var p = Directive.prototype
  34. /**
  35. * Initialize the directive instance's definition.
  36. */
  37. p._initDef = function () {
  38. var def = this.vm.$options.directives[this.name]
  39. _.extend(this, def)
  40. // init params
  41. var el = this.el
  42. var attrs = this.paramAttributes
  43. if (attrs) {
  44. var params = this.params = {}
  45. attrs.forEach(function (p) {
  46. params[p] = el.getAttribute(p)
  47. el.removeAttribute(p)
  48. })
  49. }
  50. }
  51. /**
  52. * Initialize the directive, setup the watcher,
  53. * call definition bind() and update() if present.
  54. */
  55. p._bind = function () {
  56. if (this.expression && !this.isLiteral && this.update) {
  57. this._watcher = new Watcher(
  58. this.vm,
  59. this.expression,
  60. this._update, // callback
  61. this, // callback context
  62. this.filters,
  63. this.twoway // need setter
  64. )
  65. var value = this._watcher.value
  66. if (this.bind) {
  67. this.bind()
  68. }
  69. if (this.update) {
  70. this.update(value)
  71. }
  72. } else {
  73. if (this.bind) {
  74. this.bind()
  75. }
  76. }
  77. this._bound = true
  78. }
  79. /**
  80. * Callback for the watcher.
  81. * Check locked or not before calling definition update.
  82. *
  83. * @param {*} value
  84. */
  85. p._update = function (value) {
  86. if (!this._locked) {
  87. this.update(value)
  88. }
  89. }
  90. /**
  91. * Teardown the watcher and call unbind.
  92. */
  93. p._teardown = function () {
  94. if (this._bound) {
  95. if (this.unbind) {
  96. this.unbind()
  97. }
  98. this._watcher.teardown()
  99. this._bound = false
  100. }
  101. }
  102. /**
  103. * Set the corresponding value with the setter.
  104. * This should only be used in two-way directives
  105. * e.g. v-model.
  106. *
  107. * @param {*} value
  108. * @param {Boolean} lock - prevent wrtie triggering update.
  109. * @public
  110. */
  111. p.set = function (value, lock) {
  112. if (this.twoway) {
  113. if (lock) {
  114. this._locked = true
  115. }
  116. this._watcher.set(value)
  117. if (lock) {
  118. _.nextTick(this._unlock, this)
  119. }
  120. }
  121. }
  122. module.exports = Directive