Parcourir la source

ensure dynamic method resolution for component inline v-on (fix #2670)

Evan You il y a 10 ans
Parent
commit
493aef04cb

+ 2 - 2
src/instance/api/data.js

@@ -3,7 +3,7 @@ import { del, toArray } from '../../util/index'
 import { parseText } from '../../parsers/text'
 import { parseDirective } from '../../parsers/directive'
 import { getPath } from '../../parsers/path'
-import { isSimplePath, parseExpression } from '../../parsers/expression'
+import { parseExpression } from '../../parsers/expression'
 
 const filterRE = /[^|]\|[^|]/
 
@@ -19,7 +19,7 @@ export default function (Vue) {
   Vue.prototype.$get = function (exp, asStatement) {
     var res = parseExpression(exp)
     if (res) {
-      if (asStatement && !isSimplePath(exp)) {
+      if (asStatement) {
         var self = this
         return function statementHandler () {
           self.$arguments = toArray(arguments)

+ 11 - 11
src/instance/internal/events.js

@@ -1,3 +1,4 @@
+import { isSimplePath } from '../../parsers/expression'
 import {
   inDoc,
   isArray,
@@ -31,22 +32,21 @@ export default function (Vue) {
 
   function registerComponentEvents (vm, el) {
     var attrs = el.attributes
-    var name, handler
+    var name, value, handler
     for (var i = 0, l = attrs.length; i < l; i++) {
       name = attrs[i].name
       if (eventRE.test(name)) {
         name = name.replace(eventRE, '')
-        handler = (vm._scope || vm._context).$eval(attrs[i].value, true)
-        if (typeof handler === 'function') {
-          handler._fromParent = true
-          vm.$on(name.replace(eventRE), handler)
-        } else if (process.env.NODE_ENV !== 'production') {
-          warn(
-            'v-on:' + name + '="' + attrs[i].value + '" ' +
-            'expects a function value, got ' + handler,
-            vm
-          )
+        // force the expression into a statement so that
+        // it always dynamically resolves the method to call (#2670)
+        // kinda ugly hack, but does the job.
+        value = attrs[i].value
+        if (isSimplePath(value)) {
+          value += '.apply(this, $arguments)'
         }
+        handler = (vm._scope || vm._context).$eval(value, true)
+        handler._fromParent = true
+        vm.$on(name.replace(eventRE), handler)
       }
     }
   }

+ 5 - 0
test/unit/specs/instance/events_spec.js

@@ -206,6 +206,7 @@ describe('Instance Events', function () {
     })
 
     it('compile v-on on child component', function () {
+      var spy2 = jasmine.createSpy()
       var vm = new Vue({
         el: document.createElement('div'),
         template: '<comp v-on:hook:created="onCreated" @ready="onReady" @ok="a++"></comp>',
@@ -221,12 +222,16 @@ describe('Instance Events', function () {
             compiled: function () {
               this.$emit('ready', 123)
               this.$emit('ok')
+              this.$parent.onReady = spy2
+              this.$emit('ready', 234)
             }
           }
         }
       })
       expect(spy.calls.count()).toBe(2)
       expect(spy).toHaveBeenCalledWith(123)
+      expect(spy2.calls.count()).toBe(1)
+      expect(spy2).toHaveBeenCalledWith(234)
       expect(vm.a).toBe(1)
     })