Skip to content

Commit 67a77d2

Browse files
committed
refactor v-bind:class
- revert class update mechanism due to perf regression - normalize array of (string|object) and objects into array of strings. this simplifies the scenario for the rest of the code.
1 parent fee414f commit 67a77d2

File tree

2 files changed

+47
-48
lines changed

2 files changed

+47
-48
lines changed

src/directives/internal/class.js

Lines changed: 43 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -2,74 +2,75 @@ import {
22
addClass,
33
removeClass,
44
isArray,
5-
isPlainObject
5+
isObject
66
} from '../../util/index'
77

88
export default {
99

1010
deep: true,
1111

1212
update (value) {
13-
if (value && typeof value === 'string') {
14-
this.handleObject(stringToObject(value))
15-
} else if (isPlainObject(value)) {
16-
this.handleObject(value)
17-
} else if (isArray(value)) {
18-
this.handleArray(value)
19-
} else {
13+
if (!value) {
2014
this.cleanup()
15+
} else if (typeof value === 'string') {
16+
this.setClass(value.trim().split(/\s+/))
17+
} else {
18+
this.setClass(normalize(value))
2119
}
2220
},
2321

24-
handleObject (value) {
25-
this.cleanup(value)
26-
this.prevKeys = Object.keys(value)
27-
setObjectClasses(this.el, value)
28-
},
29-
30-
handleArray (value) {
22+
setClass (value) {
3123
this.cleanup(value)
3224
for (var i = 0, l = value.length; i < l; i++) {
3325
var val = value[i]
34-
if (val && isPlainObject(val)) {
35-
setObjectClasses(this.el, val)
36-
} else if (val && typeof val === 'string') {
37-
addClass(this.el, val)
26+
if (val) {
27+
apply(this.el, val, addClass)
3828
}
3929
}
40-
this.prevKeys = value.slice()
30+
this.prevKeys = value
4131
},
4232

4333
cleanup (value) {
44-
if (!this.prevKeys) return
45-
46-
var i = this.prevKeys.length
34+
const prevKeys = this.prevKeys
35+
if (!prevKeys) return
36+
var i = prevKeys.length
4737
while (i--) {
48-
var key = this.prevKeys[i]
38+
var key = prevKeys[i]
4939
if (!key) continue
50-
51-
var keys = isPlainObject(key) ? Object.keys(key) : [key]
52-
for (var j = 0, l = keys.length; j < l; j++) {
53-
toggleClasses(this.el, keys[j], removeClass)
40+
if (key && (!value || value.indexOf(key) < 0)) {
41+
apply(this.el, key, removeClass)
5442
}
5543
}
5644
}
5745
}
5846

59-
function setObjectClasses (el, obj) {
60-
var keys = Object.keys(obj)
61-
for (var i = 0, l = keys.length; i < l; i++) {
62-
var key = keys[i]
63-
if (!obj[key]) continue
64-
toggleClasses(el, key, addClass)
65-
}
66-
}
47+
/**
48+
* Normalize objects and arrays (potentially containing objects)
49+
* into array of strings.
50+
*
51+
* @param {Object|Array<String|Object>} value
52+
* @return {Array<String>}
53+
*/
6754

68-
function stringToObject (value) {
69-
var res = {}
70-
var keys = value.trim().split(/\s+/)
71-
for (var i = 0, l = keys.length; i < l; i++) {
72-
res[keys[i]] = true
55+
function normalize (value) {
56+
const res = []
57+
if (isArray(value)) {
58+
for (var i = 0, l = value.length; i < l; i++) {
59+
const key = value[i]
60+
if (key) {
61+
if (typeof key === 'string') {
62+
res.push(key)
63+
} else {
64+
for (var k in key) {
65+
if (key[k]) res.push(k)
66+
}
67+
}
68+
}
69+
}
70+
} else if (isObject(value)) {
71+
for (var key in value) {
72+
if (value[key]) res.push(key)
73+
}
7374
}
7475
return res
7576
}
@@ -85,14 +86,12 @@ function stringToObject (value) {
8586
* @param {Function} fn
8687
*/
8788

88-
function toggleClasses (el, key, fn) {
89+
function apply (el, key, fn) {
8990
key = key.trim()
90-
9191
if (key.indexOf(' ') === -1) {
9292
fn(el, key)
9393
return
9494
}
95-
9695
// The key contains one or more space characters.
9796
// Since a class name doesn't accept such characters, we
9897
// treat it as multiple classes.

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@ describe(':class', function () {
1212
var dir = _.extend({ el: el }, def)
1313
dir.update('bar')
1414
expect(el.className).toBe('foo bar')
15-
dir.update('baz')
16-
expect(el.className).toBe('foo baz')
15+
dir.update('baz qux')
16+
expect(el.className).toBe('foo baz qux')
1717
dir.update('qux')
1818
expect(el.className).toBe('foo qux')
1919
dir.update()
@@ -52,7 +52,7 @@ describe(':class', function () {
5252
dir.update(['b', 'c'])
5353
expect(el.className).toBe('a b c')
5454
dir.update(['d', 'c'])
55-
expect(el.className).toBe('a d c')
55+
expect(el.className).toBe('a c d')
5656
dir.update()
5757
expect(el.className).toBe('a')
5858
// test mutating array
@@ -71,7 +71,7 @@ describe(':class', function () {
7171
dir.update(['f', {z: true}])
7272
expect(el.className).toBe('a f z')
7373
dir.update(['l', 'f', {n: true, z: true}])
74-
expect(el.className).toBe('a l f n z')
74+
expect(el.className).toBe('a f z l n')
7575
dir.update(['x', {}])
7676
expect(el.className).toBe('a x')
7777
dir.update()

0 commit comments

Comments
 (0)