8000 simplify prop binding modes · mikehins/vue@a6de6e9 · GitHub
[go: up one dir, main page]

Skip to content 8000

Commit a6de6e9

Browse files
committed
simplify prop binding modes
1 parent 098a3cd commit a6de6e9

File tree

7 files changed

+127
-164
lines changed

7 files changed

+127
-164
lines changed

src/compiler/compile.js

Lines changed: 19 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ var textParser = require('../parsers/text')
44
var dirParser = require('../parsers/directive')
55
var templateParser = require('../parsers/template')
66
var resolveAsset = _.resolveAsset
7+
var propBindingModes = config._propBindingModes
78

89
// internal directives
910
var propDef = require('../directives/prop')
@@ -407,7 +408,7 @@ var identRE = require('../parsers/path').identRE
407408
function compileProps (el, attrs, propNames) {
408409
var props = []
409410
var i = propNames.length
410-
var name, value, path, prop, settable, literal, single
411+
var name, value, path, prop, literal, single
411412
while (i--) {
412413
name = propNames[i]
413414
// props could contain dashes, which will be
@@ -435,7 +436,8 @@ function compileProps (el, attrs, propNames) {
435436
prop = {
436437
name: name,
437438
raw: value,
438-
path: path
439+
path: path,
440+
mode: propBindingModes.ONE_WAY
439441
}
440442
var tokens = textParser.parse(value)
441443
if (tokens) {
@@ -451,21 +453,20 @@ function compileProps (el, attrs, propNames) {
451453
single = tokens.length === 1
452454
literal = literalValueRE.test(prop.parentPath)
453455
// one time: {{* prop}}
454-
prop.oneTime =
455-
literal ||
456-
(single && tokens[0].oneTime)
457-
// check one-way bindings
458-
if (!prop.oneTime) {
459-
settable = !literal && settablePathRE.test(prop.parentPath)
460-
// one way down: {{> prop}}
461-
prop.oneWayDown =
462-
!settable ||
463-
(single && tokens[0].oneWay === 60) // <
464-
// one way up: {{< prop}}
465-
prop.oneWayUp =
466-
single &&
467-
settable &&
468-
tokens[0].oneWay === 62 // >
456+
if (literal || (single && tokens[0].oneTime)) {
457+
prop.mode = propBindingModes.ONE_TIME
458+
} else if (
459+
!literal &&
460+
(single && tokens[0].twoWay)
461+
) {
462+
if (settablePathRE.test(prop.parentPath)) {
463+
prop.mode = propBindingModes.TWO_WAY
464+
} else {
465+
_.warn(
466+
'Cannot bind two-way prop with non-settable ' +
467+
'parent path: ' + prop.parentPath
468+
)
469+
}
469470
}
470471
}
471472
props.push(prop)
@@ -490,7 +491,7 @@ function makePropsLinkFn (props) {
490491
path = prop.path
491492
if (prop.dynamic) {
492493
if (vm.$parent) {
493-
if (prop.oneTime) {
494+
if (prop.mode === propBindingModes.ONE_TIME) {
494495
// one time binding
495496
vm.$set(path, vm.$parent.$get(prop.parentPath))
496497
} else {

src/config.js

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,17 @@ module.exports = {
7575
'elementDirective',
7676
'filter',
7777
'transition'
78-
]
78+
],
79+
80+
/**
81+
* prop binding modes
82+
*/
83+
84+
_propBindingModes: {
85+
ONE_WAY: 0,
86+
TWO_WAY: 1,
87+
ONE_TIME: 2
88+
}
7989

8090
}
8191

@@ -96,4 +106,4 @@ Object.defineProperty(module.exports, 'delimiters', {
96106
delimiters = val
97107
this._delimitersChanged = true
98108
}
99-
})
109+
})

src/directives/prop.js

Lines changed: 20 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
var Watcher = require('../watcher')
2+
var bindingModes = require('../config')._propBindingModes
23

34
module.exports = {
45

@@ -16,30 +17,28 @@ module.exports = {
1617
// sure it doesn't cause other watchers to re-evaluate.
1718
var locked = false
1819

19-
if (!prop.oneWayUp) {
20-
this.parentWatcher = new Watcher(
21-
parent,
22-
parentKey,
23-
function (val) {
24-
if (!locked) {
25-
locked = true
26-
// all props have been initialized already
27-
child[childKey] = val
28-
locked = false
29-
}
30-
},
31-
{ sync: true }
32-
)
33-
34-
// set the child initial value first, before setting
35-
// up the child watcher to avoid triggering it
36-
// immediately.
37-
child.$set(childKey, this.parentWatcher.value)
38-
}
20+
this.parentWatcher = new Watcher(
21+
parent,
22+
parentKey,
23+
function (val) {
24+
if (!locked) {
25+
locked = true
26+
// all props have been initialized already
27+
child[childKey] = val
28+
locked = false
29+
}
30+
},
31+
{ sync: true }
32+
)
33+
34+
// set the child initial value first, before setting
35+
// up the child watcher to avoid triggering it
36+
// immediately.
37+
child.$set(childKey, this.parentWatcher.value)
3938

4039
// only setup two-way binding if this is not a one-way
4140
// binding.
42-
if (!prop.oneWayDown) {
41+
if (prop.mode === bindingModes.TWO_WAY) {
4342
this.childWatcher = new Watcher(
4443
child,
4544
childKey,
@@ -52,11 +51,6 @@ module.exports = {
5251
},
5352
{ sync: true }
5453
)
55-
56-
// set initial value for one-way up binding
57-
if (prop.oneWayUp) {
58-
parent.$set(parentKey, this.childWatcher.value)
59-
}
6054
}
6155
},
6256

src/parsers/text.js

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ exports.parse = function (text) {
7070
}
7171
var tokens = []
7272
var lastIndex = tagRE.lastIndex = 0
73-
var match, index, value, first, oneTime, oneWay
73+
var match, index, value, first, oneTime, twoWay
7474
/* jshint boss:true */
7575
while (match = tagRE.exec(text)) {
7676
index = match.index
@@ -82,17 +82,17 @@ exports.parse = function (text) {
8282
}
8383
// tag token
8484
first = match[1].charCodeAt(0)
85-
oneTime = first === 42 // *
86-
oneWay = first === 62 || first === 60 // > or <
87-
value = oneTime || oneWay
85+
oneTime = first === 42 // *
86+
twoWay = first === 64 // @
87+
value = oneTime || twoWay
8888
? match[1].slice(1)
8989
: match[1]
9090
tokens.push({
9191
tag: true,
9292
value: value.trim(),
9393
html: htmlRE.test(match[0]),
9494
oneTime: oneTime,
95-
oneWay: oneWay ? first : 0
95+
twoWay: twoWay
9696
})
9797
lastIndex = index + match[0].length
9898
}

test/unit/specs/compiler/compile_spec.js

F438
Lines changed: 11 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,7 @@ if (_.inBrowser) {
146146
})
147147

148148
it('props', function () {
149+
var bindingModes = Vue.config._propBindingModes
149150
var options = _.mergeOptions(Vue.options, {
150151
_asComponent: true,
151152
props: [
@@ -154,8 +155,7 @@ if (_.inBrowser) {
154155
'some-other-attr',
155156
'multiple-attrs',
156157
'onetime',
157-
'oneway-up',
158-
'oneway-down',
158+
'twoway',
159159
'with-filter',
160160
'camelCase',
161161
'boolean-literal'
@@ -167,52 +167,44 @@ if (_.inBrowser) {
167167
el.setAttribute('some-other-attr', '2')
168168
el.setAttribute('multiple-attrs', 'a {{b}} c')
169169
el.setAttribute('onetime', '{{*a}}')
170-
el.setAttribute('oneway-up', '{{>a}}')
171-
el.setAttribute('oneway-down', '{{<a}}')
170+
el.setAttribute('twoway', '{{@a}}')
172171
el.setAttribute('with-filter', '{{a | filter}}')
173172
el.setAttribute('boolean-literal', '{{true}}')
174173
transclude(el, options)
175174
compiler.compileAndLinkRoot(vm, el, options)
176175
// should skip literals and one-time bindings
177-
expect(vm._bindDir.calls.count()).toBe(5)
176+
expect(vm._bindDir.calls.count()).toBe(4)
178177
// data-some-attr
179178
var args = vm._bindDir.calls.argsFor(0)
180179
expect(args[0]).toBe('prop')
181180
expect(args[1]).toBe(null)
182181
expect(args[2].path).toBe('someAttr')
183182
expect(args[2].parentPath).toBe('a')
183+
expect(args[2].mode).toBe(bindingModes.ONE_WAY)
184184
expect(args[3]).toBe(def)
185185
// multiple-attrs
186186
args = vm._bindDir.calls.argsFor(1)
187187
expect(args[0]).toBe('prop')
188188
expect(args[1]).toBe(null)
189189
expect(args[2].path).toBe('multipleAttrs')
190190
expect(args[2].parentPath).toBe('"a "+(b)+" c"')
191+
expect(args[2].mode).toBe(bindingModes.ONE_WAY)
191192
expect(args[3]).toBe(def)
192-
// one way up
193+
// two way
193194
args = vm._bindDir.calls.argsFor(2)
194195
expect(args[0]).toBe('prop')
195196
expect(args[1]).toBe(null)
196-
expect(args[2].path).toBe('onewayUp')
197-
expect(args[2].oneWayUp).toBe(true)
198-
expect(args[2].oneWayDown).toBe(false)
199-
expect(args[2].parentPath).toBe('a')
200-
expect(args[3]).toBe(def)
201-
// one way down
202-
args = vm._bindDir.calls.argsFor(3)
203-
expect(args[0]).toBe('prop')
204-
expect(args[1]).toBe(null)
205-
expect(args[2].path).toBe('onewayDown')
206-
expect(args[2].oneWayUp).toBe(false)
207-
expect(args[2].oneWayDown).toBe(true)
197+
expect(args[2].path).toBe('twoway')
198+
expect(args[2].mode).toBe(bindingModes.TWO_WAY)
208199
expect(args[2].parentPath).toBe('a')
209200
expect(args[3]).toBe(def)
210201
// with-filter
211-
args = vm._bindDir.calls.argsFor(4)
202+
args = vm._bindDir.calls.argsFor(3)
212203
expect(args[0]).toBe('prop')
213204
expect(args[1]).toBe(null)
214205
expect(args[2].path).toBe('withFilter')
215206
expect(args[2].parentPath).toBe('this._applyFilters(a,null,[{"name":"filter"}],false)')
207+
expect(args[2].mode).toBe(bindingModes.ONE_WAY)
216208
expect(args[3]).toBe(def)
217209
// camelCase should've warn
218210
expect(hasWarned(_, 'using camelCase')).toBe(true)

0 commit comments

Comments
 (0)
0