Browse Source

add `watch` option

Evan You 11 years ago
parent
commit
540da662bc
5 changed files with 94 additions and 27 deletions
  1. 4 0
      changes.md
  2. 32 20
      src/instance/events.js
  3. 3 3
      src/instance/init.js
  4. 4 3
      src/util/merge-option.js
  5. 51 1
      test/unit/specs/instance/events_spec.js

+ 4 - 0
changes.md

@@ -102,6 +102,10 @@ By default, all child components **DO NOT** inherit the parent scope. Only anony
   // -> goodbye!
   ```
 
+- #### new option: `watch`.
+
+  Similar to the new `events` option, the `watch` option accepts an object of expression/callback pairs. The instance will automatically call `$watch` for each entry in the object. You can also use a method name string instead of a callback.
+
 - #### new option: `inherit`.
 
   Default: `false`.

+ 32 - 20
src/instance/events.js

@@ -2,51 +2,63 @@ var _ = require('../util')
 var inDoc = _.inDoc
 
 /**
- * Setup the instance's option events.
+ * Setup the instance's option events & watchers.
  * If the value is a string, we pull it from the
  * instance's methods by name.
  */
 
 exports._initEvents = function () {
   var options = this.$options
-  var events = options.events
-  var methods = options.methods
-  if (events) {
-    var handlers, e, i, j
-    for (e in events) {
-      handlers = events[e]
-      if (_.isArray(handlers)) {
-        for (i = 0, j = handlers.length; i < j; i++) {
-          register(this, e, handlers[i], methods)
-        }
-      } else {
-        register(this, e, handlers, methods)
+  registerCallbacks(this, '$on', options.events)
+  registerCallbacks(this, '$watch', options.watch)
+}
+
+/**
+ * Register callbacks for option events and watchers.
+ *
+ * @param {Vue} vm
+ * @param {String} action
+ * @param {Object} hash
+ */
+
+function registerCallbacks (vm, action, hash) {
+  if (!hash) return
+  var handlers, key, i, j
+  for (key in hash) {
+    handlers = hash[key]
+    if (_.isArray(handlers)) {
+      for (i = 0, j = handlers.length; i < j; i++) {
+        register(vm, action, key, handlers[i])
       }
+    } else {
+      register(vm, action, key, handlers)
     }
   }
 }
 
 /**
- * Helper to register an event.
+ * Helper to register an event/watch callback.
  *
  * @param {Vue} vm
- * @param {String} event
+ * @param {String} action
+ * @param {String} key
  * @param {*} handler
- * @param {Object|undefined} methods
  */
 
-function register (vm, event, handler, methods) {
+function register (vm, action, key, handler) {
   var type = typeof handler
   if (type === 'function') {
-    vm.$on(event, handler)
+    vm[action](key, handler)
   } else if (type === 'string') {
+    var methods = vm.$options.methods
     var method = methods && methods[handler]
     if (method) {
-      vm.$on(event, method)
+      vm[action](key, method)
     } else {
       _.warn(
         'Unknown method: "' + handler + '" when ' +
-        'registering callback for event: "' + event + '".'
+        'registering callback for ' + action +
+        ': "' + key + '".'
       )
     }
   }

+ 3 - 3
src/instance/init.js

@@ -60,12 +60,12 @@ exports._init = function (options) {
   // set data after merge.
   this._data = options.data || {}
 
-  // setup event system and option events.
-  this._initEvents()
-
   // initialize data observation and scope inheritance.
   this._initScope()
 
+  // setup event system and option events.
+  this._initEvents()
+
   // call created hook
   this._callHook('created')
 

+ 4 - 3
src/util/merge-option.js

@@ -126,12 +126,13 @@ strats.components = function (parentVal, childVal, vm, key) {
 }
 
 /**
- * Events
+ * Events & Watchers.
  *
- * Events should not overwrite one another, so we merge
- * them as arrays.
+ * Events & watchers hashes should not overwrite one
+ * another, so we merge them as arrays.
  */
 
+strats.watch =
 strats.events = function (parentVal, childVal) {
   if (!childVal) return parentVal
   if (!parentVal) return childVal

+ 51 - 1
test/unit/specs/instance/events_spec.js

@@ -10,7 +10,7 @@ describe('Instance Events', function () {
     spyOn(_, 'warn')
   })
 
-  describe('events', function () {
+  describe('option events', function () {
 
     it('normal events', function () {
       var vm = new Vue({
@@ -52,6 +52,56 @@ describe('Instance Events', function () {
 
   })
 
+  describe('option watchers', function () {
+
+    it('normal', function (done) {
+      var spyA = jasmine.createSpy()
+      var spyB = jasmine.createSpy()
+      var vm = new Vue({
+        watch: {
+          'a.b.c': spyA,
+          'b + c': spyB
+        },
+        data: {
+          a: {
+            b: { c: 1 }
+          },
+          b: 1,
+          c: 2
+        }
+      })
+      vm.a.b.c = 2
+      vm.b = 3
+      vm.c = 4
+      _.nextTick(function () {
+        expect(spyA).toHaveBeenCalledWith(2, 1)
+        expect(spyB).toHaveBeenCalledWith(7, 3)
+        done()
+      })
+    })
+
+    it('method name strings', function (done) {
+      var spy = jasmine.createSpy()
+      var vm = new Vue({
+        watch: {
+          'a': 'test'
+        },
+        data: {
+          a: 1
+        },
+        methods: {
+          test: spy
+        }
+      })
+      vm.a = 2
+      _.nextTick(function () {
+        expect(spy).toHaveBeenCalledWith(2, 1)
+        done()
+      })
+    })
+
+  })
+
   describe('hooks', function () {
     
     it('created', function () {