Skip to content

Commit 02655cd

Browse files
committed
props: adjust props merging strategy (fix vuejs#1431)
1 parent 9af9c29 commit 02655cd

File tree

5 files changed

+73
-49
lines changed

5 files changed

+73
-49
lines changed

src/compiler/compile-props.js

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ var _ = require('../util')
22
var dirParser = require('../parsers/directive')
33
var propDef = require('../directives/internal/prop')
44
var propBindingModes = require('../config')._propBindingModes
5+
var empty = {}
56

67
// regexes
78
var identRE = require('../parsers/path').identRE
@@ -18,11 +19,12 @@ var settablePathRE = /^[A-Za-z_$][\w$]*(\.[A-Za-z_$][\w$]*|\[[^\[\]]+\])*$/
1819

1920
module.exports = function compileProps (el, propOptions) {
2021
var props = []
21-
var i = propOptions.length
22+
var names = Object.keys(propOptions)
23+
var i = names.length
2224
var options, name, attr, value, path, parsed, prop
2325
while (i--) {
24-
options = propOptions[i]
25-
name = options.name
26+
name = names[i]
27+
options = propOptions[name] || empty
2628

2729
if (process.env.NODE_ENV !== 'production' && name === '$data') {
2830
_.warn('Do not use $data as prop.')

src/util/options.js

Lines changed: 19 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -116,8 +116,7 @@ strats.detached =
116116
strats.beforeCompile =
117117
strats.compiled =
118118
strats.beforeDestroy =
119-
strats.destroyed =
120-
strats.props = function (parentVal, childVal) {
119+
strats.destroyed = function (parentVal, childVal) {
121120
return childVal
122121
? parentVal
123122
? parentVal.concat(childVal)
@@ -188,11 +187,13 @@ strats.events = function (parentVal, childVal) {
188187
* Other object hashes.
189188
*/
190189

190+
strats.props =
191191
strats.methods =
192192
strats.computed = function (parentVal, childVal) {
193193
if (!childVal) return parentVal
194194
if (!parentVal) return childVal
195-
var ret = Object.create(parentVal)
195+
var ret = Object.create(null)
196+
extend(ret, parentVal)
196197
extend(ret, childVal)
197198
return ret
198199
}
@@ -247,21 +248,22 @@ function guardComponents (options) {
247248

248249
function guardProps (options) {
249250
var props = options.props
250-
if (_.isPlainObject(props)) {
251-
options.props = Object.keys(props).map(function (key) {
252-
var val = props[key]
253-
if (!_.isPlainObject(val)) {
254-
val = { type: val }
251+
var i
252+
if (_.isArray(props)) {
253+
options.props = {}
254+
i = props.length
255+
while (i--) {
256+
options.props[props[i]] = null
257+
}
258+
} else if (_.isPlainObject(props)) {
259+
var keys = Object.keys(props)
260+
i = keys.length
261+
while (i--) {
262+
var val = props[keys[i]]
263+
if (typeof val === 'function') {
264+
props[keys[i]] = { type: val }
255265
}
256-
val.name = key
257-
return val
258-
})
259-
} else if (_.isArray(props)) {
260-
options.props = props.map(function (prop) {
261-
return typeof prop === 'string'
262-
? { name: prop }
263-
: prop
264-
})
266+
}
265267
}
266268
}
267269

test/unit/specs/compiler/compile_spec.js

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -239,14 +239,14 @@ if (_.inBrowser) {
239239

240240
it('props', function () {
241241
var bindingModes = Vue.config._propBindingModes
242-
var props = [
243-
{ name: 'testNormal' },
244-
{ name: 'testLiteral' },
245-
{ name: 'testTwoWay' },
246-
{ name: 'twoWayWarn' },
247-
{ name: 'testOneTime' },
248-
{ name: 'optimizeLiteral' }
249-
]
242+
var props = {
243+
testNormal: null,
244+
testLiteral: null,
245+
testTwoWay: null,
246+
twoWayWarn: null,
247+
testOneTime: null,
248+
optimizeLiteral: null
249+
}
250250
el.innerHTML = '<div ' +
251251
'v-bind:test-normal="a" ' +
252252
'test-literal="1" ' +
@@ -288,10 +288,7 @@ if (_.inBrowser) {
288288
vm._context = null
289289
el.setAttribute('v-bind:a', '"hi"')
290290
el.setAttribute(':b', 'hi')
291-
compiler.compileAndLinkProps(vm, el, [
292-
{ name: 'a' },
293-
{ name: 'b' }
294-
])
291+
compiler.compileAndLinkProps(vm, el, { a: null, b: null })
295292
expect(vm._bindDir.calls.count()).toBe(0)
296293
expect(vm._data.a).toBe('hi')
297294
expect(hasWarned(_, 'Cannot bind dynamic prop on a root')).toBe(true)

test/unit/specs/directives/internal/prop_spec.js

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -306,13 +306,12 @@ if (_.inBrowser) {
306306
},
307307
components: {
308308
test: {
309-
props: [
310-
{
311-
name: 'test',
309+
props: {
310+
test: {
312311
type: type,
313312
validator: validator
314313
}
315-
]
314+
}
316315
}
317316
}
318317
})
@@ -400,12 +399,9 @@ if (_.inBrowser) {
400399
template: '<test></test>',
401400
components: {
402401
test: {
403-
props: [
404-
{
405-
name: 'prop',
406-
required: true
407-
}
408-
]
402+
props: {
403+
prop: { required: true }
404+
}
409405
}
410406
}
411407
})

test/unit/specs/util/options_spec.js

Lines changed: 34 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ describe('Util - Option merging', function () {
1818
expect(res).toBe(false)
1919
})
2020

21-
it('hooks & props', function () {
21+
it('hooks', function () {
2222
var fn1 = function () {}
2323
var fn2 = function () {}
2424
var res
@@ -38,12 +38,6 @@ describe('Util - Option merging', function () {
3838
expect(res.length).toBe(2)
3939
expect(res[0]).toBe(fn1)
4040
expect(res[1]).toBe(fn2)
41-
// both arrays
42-
res = merge({props: [1]}, {props: [2]}).props
43-
expect(Array.isArray(res)).toBe(true)
44-
expect(res.length).toBe(2)
45-
expect(res[0]).toBe(1)
46-
expect(res[1]).toBe(2)
4741
})
4842

4943
it('events', function () {
@@ -114,6 +108,39 @@ describe('Util - Option merging', function () {
114108
expect(res.b).toBe(asset2)
115109
})
116110

111+
it('props', function () {
112+
var res = merge({
113+
props: {
114+
a: null,
115+
d: null
116+
}
117+
}, {
118+
props: {
119+
a: { required: true },
120+
b: Boolean,
121+
c: { type: Array }
122+
}
123+
})
124+
expect(typeof res.props.a).toBe('object')
125+
expect(res.props.a.required).toBe(true)
126+
expect(typeof res.props.b).toBe('object')
127+
expect(res.props.b.type).toBe(Boolean)
128+
expect(typeof res.props.c).toBe('object')
129+
expect(res.props.c.type).toBe(Array)
130+
expect(res.props.d).toBe(null)
131+
132+
// check array syntax
133+
res = merge({
134+
props: {
135+
b: null
136+
}
137+
}, {
138+
props: ['a']
139+
})
140+
expect(res.props.a).toBe(null)
141+
expect(res.props.b).toBe(null)
142+
})
143+
117144
it('guard components', function () {
118145
var res = merge({
119146
components: null

0 commit comments

Comments
 (0)