Skip to content

Commit 4e3fb0d

Browse files
committed
Directive: use new params API
1 parent 9c45702 commit 4e3fb0d

File tree

12 files changed

+141
-111
lines changed

12 files changed

+141
-111
lines changed

src/directive.js

Lines changed: 73 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,9 @@ Directive.prototype._bind = function () {
7777
_.extend(this, def)
7878
}
7979

80+
// setup directive params
81+
this._setupParams()
82+
8083
// initial bind
8184
if (this.bind) {
8285
this.bind()
@@ -131,6 +134,65 @@ Directive.prototype._bind = function () {
131134
this._bound = true
132135
}
133136

137+
/**
138+
* Setup all param attributes, e.g. track-by,
139+
* transition-mode, etc...
140+
*/
141+
142+
Directive.prototype._setupParams = function () {
143+
if (!this.params) {
144+
return
145+
}
146+
var params = this.params
147+
// swap the params array with a fresh object.
148+
this.params = Object.create(null)
149+
var i = params.length
150+
var key, val, mappedKey
151+
while (i--) {
152+
key = params[i]
153+
mappedKey = _.camelize(key)
154+
val = _.attr(this.el, key)
155+
if (val != null) {
156+
// static
157+
this.params[mappedKey] = val === '' ? true : val
158+
} else {
159+
// dynamic
160+
val = _.getBindAttr(this.el, key)
161+
if (val != null) {
162+
this._setupParamWatcher(mappedKey, val)
163+
}
164+
}
165+
}
166+
}
167+
168+
/**
169+
* Setup a watcher for a dynamic param.
170+
*
171+
* @param {String} key
172+
* @param {String} expression
173+
*/
174+
175+
Directive.prototype._setupParamWatcher = function (key, expression) {
176+
var self = this
177+
var called = false
178+
var unwatch = (this._scope || this.vm).$watch(expression, function (val, oldVal) {
179+
self.params[key] = val
180+
// since we are in immediate mode,
181+
// only call the param change callbacks if this is not the first update.
182+
if (called) {
183+
var cb = self.paramWatchers && self.paramWatchers[key]
184+
if (cb) {
185+
cb.call(self, val, oldVal)
186+
}
187+
} else {
188+
called = true
189+
}
190+
}, {
191+
immediate: true
192+
})
193+
;(this._paramUnwatchFns || (this._paramUnwatchFns = [])).push(unwatch)
194+
}
195+
134196
/**
135197
* Check if the directive is a function caller
136198
* and if the expression is a callable one. If both true,
@@ -161,30 +223,6 @@ Directive.prototype._checkStatement = function () {
161223
}
162224
}
163225

164-
/**
165-
* Check for an attribute directive param, e.g. lazy
166-
*
167-
* @param {String} name
168-
* @return {String}
169-
*/
170-
171-
Directive.prototype.param = function (name) {
172-
var param = _.attr(this.el, name)
173-
if (param != null) {
174-
param = (this._scope || this.vm).$interpolate(param)
175-
} else {
176-
param = _.getBindAttr(this.el, name)
177-
if (param != null) {
178-
param = (this._scope || this.vm).$eval(param)
179-
process.env.NODE_ENV !== 'production' && _.log(
180-
'You are using bind- syntax on "' + name + '", which ' +
181-
'is a directive param. It will be evaluated only once.'
182-
)
183-
}
184-
}
185-
return param
186-
}
187-
188226
/**
189227
* Set the corresponding value with the setter.
190228
* This should only be used in two-way directives
@@ -253,13 +291,21 @@ Directive.prototype._teardown = function () {
253291
this._watcher.teardown()
254292
}
255293
var listeners = this._listeners
294+
var i
256295
if (listeners) {
257-
for (var i = 0; i < listeners.length; i++) {
296+
i = listeners.length
297+
while (i--) {
258298
_.off(this.el, listeners[i][0], listeners[i][1])
259299
}
260300
}
261-
this.vm = this.el =
262-
this._watcher = this._listeners = null
301+
var unwatchFns = this._paramUnwatchFns
302+
if (unwatchFns) {
303+
i = unwatchFns.length
304+
while (i--) {
305+
unwatchFns[i]()
306+
}
307+
}
308+
this.vm = this.el = this._watcher = this._listeners = null
263309
}
264310
}
265311

src/directives/element/partial.js

Lines changed: 13 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,27 @@
11
var _ = require('../../util')
2-
var FragmentFactory = require('../../fragment/factory')
32
var vIf = require('../public/if')
4-
var Watcher = require('../../watcher')
3+
var FragmentFactory = require('../../fragment/factory')
54

65
module.exports = {
76

87
priority: 1750,
98

10-
bind: function () {
11-
var el = this.el
12-
this.anchor = _.createAnchor('v-partial')
13-
_.replace(el, this.anchor)
14-
var id = el.getAttribute('name')
15-
if (id != null) {
16-
// static partial
17-
this.insert(id)
18-
} else {
19-
id = _.getBindAttr(el, 'name')
20-
if (id) {
21-
this.setupDynamic(id)
22-
}
23-
}
24-
},
9+
params: ['name'],
2510

26-
setupDynamic: function (exp) {
27-
var self = this
28-
var onNameChange = function (value) {
29-
vIf.remove.call(self)
11+
// watch changes to name for dynamic partials
12+
paramWatchers: {
13+
name: function (value) {
14+
vIf.remove.call(this)
3015
if (value) {
31-
self.insert(value)
16+
this.insert(value)
3217
}
3318
}
34-
this.nameWatcher = new Watcher(this.vm, exp, onNameChange, {
35-
scope: this._scope
36-
})
37-
onNameChange(this.nameWatcher.value)
19+
},
20+
21+
bind: function () {
22+
this.anchor = _.createAnchor('v-partial')
23+
_.replace(this.el, this.anchor)
24+
this.insert(this.params.name)
3825
},
3926

4027
insert: function (id) {
@@ -52,8 +39,5 @@ module.exports = {
5239
if (this.frag) {
5340
this.frag.destroy()
5441
}
55-
if (this.nameWatcher) {
56-
this.nameWatcher.teardown()
57-
}
5842
}
5943
}

src/directives/element/slot.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ module.exports = {
1010

1111
priority: 1750,
1212

13+
params: ['name'],
14+
1315
bind: function () {
1416
var host = this.vm
1517
var raw = host.$options._content
@@ -19,7 +21,7 @@ module.exports = {
1921
return
2022
}
2123
var context = host._context
22-
var slotName = this.param('name')
24+
var slotName = this.params.name
2325
if (!slotName) {
2426
// Default content
2527
var self = this

src/directives/internal/component.js

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,12 @@ module.exports = {
55

66
priority: 1500,
77

8+
params: [
9+
'keep-alive',
10+
'transition-mode',
11+
'inline-template'
12+
],
13+
814
/**
915
* Setup. Two possible usages:
1016
*
@@ -17,25 +23,19 @@ module.exports = {
1723

1824
bind: function () {
1925
if (!this.el.__vue__) {
20-
// check keep-alive options.
21-
// If yes, instead of destroying the active vm when
22-
// hiding (v-if) or switching (dynamic literal) it,
23-
// we simply remove it from the DOM and save it in a
24-
// cache object, with its constructor id as the key.
25-
this.keepAlive = this.param('keep-alive') != null
26-
2726
// check ref
2827
this.ref = _.findRef(this.el)
2928
var refs = (this._scope || this.vm).$refs
3029
if (this.ref && !refs.hasOwnProperty(this.ref)) {
3130
_.defineReactive(refs, this.ref, null)
3231
}
33-
32+
// keep-alive cache
33+
this.keepAlive = this.params.keepAlive
3434
if (this.keepAlive) {
3535
this.cache = {}
3636
}
3737
// check inline-template
38-
if (this.param('inline-template') !== null) {
38+
if (this.params.inlineTemplate) {
3939
// extract inline template as a DocumentFragment
4040
this.inlineTemplate = _.extractContent(this.el, true)
4141
}
@@ -49,7 +49,6 @@ module.exports = {
4949
// create a ref anchor
5050
this.anchor = _.createAnchor('v-component')
5151
_.replace(this.el, this.anchor)
52-
this.transMode = this.param('transition-mode')
5352
// if static, build right now.
5453
if (this.literal) {
5554
this.setComponent(this.expression)
@@ -296,7 +295,7 @@ module.exports = {
296295
var self = this
297296
var current = this.childVM
298297
this.childVM = target
299-
switch (self.transMode) {
298+
switch (self.params.transitionMode) {
300299
case 'in-out':
301300
target.$before(self.anchor, function () {
302301
self.remove(current, cb)

src/directives/public/bind.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,14 @@ module.exports = {
2929

3030
bind: function () {
3131
var attr = this.arg
32+
var tag = this.el.tagName
3233
// handle interpolation bindings
3334
if (this.descriptor.interp) {
3435
// only allow binding on native attributes
35-
if (disallowedInterpAttrRE.test(attr)) {
36+
if (
37+
disallowedInterpAttrRE.test(attr) ||
38+
(attr === 'name' && (tag === 'PARTIAL' || tag === 'SLOT'))
39+
) {
3640
process.env.NODE_ENV !== 'production' && _.warn(
3741
attr + '="' + this.descriptor.raw + '": ' +
3842
'attribute interpolation is not allowed in Vue.js ' +

0 commit comments

Comments
 (0)