@@ -85,21 +85,36 @@ export default function (Vue) {
8585 /**
8686 * Trigger an event on self.
8787 *
88- * @param {String } event
88+ * @param {String|Object } event
8989 * @return {Boolean } shouldPropagate
9090 */
9191
9292 Vue . prototype . $emit = function ( event ) {
93+ var isSource = typeof event === 'string'
94+ event = isSource
95+ ? event
96+ : event . name
9397 var cbs = this . _events [ event ]
94- var shouldPropagate = ! cbs
98+ var shouldPropagate = isSource || ! cbs
9599 if ( cbs ) {
96100 cbs = cbs . length > 1
97101 ? toArray ( cbs )
98102 : cbs
103+ // this is a somewhat hacky solution to the question raised
104+ // in #2102: for an inline component listener like <comp @test="doThis">,
105+ // the propagation handling is somewhat broken. Therefore we
106+ // need to treat these inline callbacks differently.
107+ var hasParentCbs = isSource && cbs . some ( function ( cb ) {
108+ return cb . _fromParent
109+ } )
110+ if ( hasParentCbs ) {
111+ shouldPropagate = false
112+ }
99113 var args = toArray ( arguments , 1 )
100114 for ( var i = 0 , l = cbs . length ; i < l ; i ++ ) {
101- var res = cbs [ i ] . apply ( this , args )
102- if ( res === true ) {
115+ var cb = cbs [ i ]
116+ var res = cb . apply ( this , args )
117+ if ( res === true && ( ! hasParentCbs || cb . _fromParent ) ) {
103118 shouldPropagate = true
104119 }
105120 }
@@ -110,20 +125,30 @@ export default function (Vue) {
110125 /**
111126 * Recursively broadcast an event to all children instances.
112127 *
113- * @param {String } event
128+ * @param {String|Object } event
114129 * @param {...* } additional arguments
115130 */
116131
117132 Vue . prototype . $broadcast = function ( event ) {
133+ var isSource = typeof event === 'string'
134+ event = isSource
135+ ? event
136+ : event . name
118137 // if no child has registered for this event,
119138 // then there's no need to broadcast.
120139 if ( ! this . _eventsCount [ event ] ) return
121140 var children = this . $children
141+ var args = toArray ( arguments )
142+ if ( isSource ) {
143+ // use object event to indicate non-source emit
144+ // on children
145+ args [ 0 ] = { name : event , source : this }
146+ }
122147 for ( var i = 0 , l = children . length ; i < l ; i ++ ) {
123148 var child = children [ i ]
124- var shouldPropagate = child . $emit . apply ( child , arguments )
149+ var shouldPropagate = child . $emit . apply ( child , args )
125150 if ( shouldPropagate ) {
126- child . $broadcast . apply ( child , arguments )
151+ child . $broadcast . apply ( child , args )
127152 }
128153 }
129154 return this
@@ -136,11 +161,16 @@ export default function (Vue) {
136161 * @param {...* } additional arguments
137162 */
138163
139- Vue . prototype . $dispatch = function ( ) {
140- this . $emit . apply ( this , arguments )
164+ Vue . prototype . $dispatch = function ( event ) {
165+ var shouldPropagate = this . $emit . apply ( this , arguments )
166+ if ( ! shouldPropagate ) return
141167 var parent = this . $parent
168+ var args = toArray ( arguments )
169+ // use object event to indicate non-source emit
170+ // on parents
171+ args [ 0 ] = { name : event , source : this }
142172 while ( parent ) {
143- var shouldPropagate = parent . $emit . apply ( parent , arguments )
173+ shouldPropagate = parent . $emit . apply ( parent , args )
144174 parent = shouldPropagate
145175 ? parent . $parent
146176 : null
0 commit comments