Skip to content

Commit c14d73e

Browse files
ktsnyyx990803
authored andcommitted
Enable to collect inital class properties as vue instance data (vuejs#29)
* collect inital class properties as vue instance data * update example * update readme to describe data can be declared as class properties * add class property example using props value * use vm instance as prototype instead of Component.prototype
1 parent ccf97e1 commit c14d73e

File tree

5 files changed

+89
-17
lines changed

5 files changed

+89
-17
lines changed

README.md

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,11 @@ Note:
1414

1515
2. Computed properties can be declared as class property accessors.
1616

17-
3. `data`, `render` and all Vue lifecycle hooks can be directly declared as class member methods as well, but you cannot invoke them on the instance itself. When declaring custom methods, you should avoid these reserved names.
17+
3. Initial `data` can be declared as class properties ([babel-plugin-transform-class-properties](https://babeljs.io/docs/plugins/transform-class-properties/) is required if you use Babel).
1818

19-
4. For all other options, pass them to the decorator function.
19+
4. `data`, `render` and all Vue lifecycle hooks can be directly declared as class member methods as well, but you cannot invoke them on the instance itself. When declaring custom methods, you should avoid these reserved names.
20+
21+
5. For all other options, pass them to the decorator function.
2022

2123
``` js
2224
import Component from 'vue-class-component'
@@ -30,18 +32,18 @@ import Component from 'vue-class-component'
3032
<input v-model="msg">
3133
<p>prop: {{propMessage}}</p>
3234
<p>msg: {{msg}}</p>
35+
<p>helloMsg: {{helloMsg}}</p>
3336
<p>computed msg: {{computedMsg}}</p>
3437
<button @click="greet">Greet</button>
3538
</div>
3639
`
3740
})
3841
class App {
39-
// return initial data
40-
data () {
41-
return {
42-
msg: 123
43-
}
44-
}
42+
// initial data
43+
msg = 123
44+
45+
// use prop values for initial data
46+
helloMsg = 'Hello, ' + this.propMessage
4547

4648
// lifecycle hook
4749
mounted () {

example/example.ts

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,8 @@ import Component from '../lib/index'
88
})
99
class App extends Vue {
1010
propMessage: string
11-
msg: number
12-
13-
// return initial data
14-
data () {
15-
return {
16-
msg: 123
17-
}
18-
}
11+
msg: number = 123
12+
helloMsg: string = 'Hello, ' + this.propMessage
1913

2014
// lifecycle hook
2115
mounted () {
@@ -45,6 +39,7 @@ class App extends Vue {
4539
}),
4640
h('p', ['prop: ', this.propMessage]),
4741
h('p', ['msg: ', this.msg]),
42+
h('p', ['helloMsg: ', this.helloMsg]),
4843
h('p', ['computed msg: ', this.computedMsg]),
4944
h('button', { on: { click: this.greet }}, ['Greet'])
5045
])
@@ -55,5 +50,5 @@ class App extends Vue {
5550
// mount
5651
new App({
5752
el: '#el',
58-
render: h => h(App, { props: { propMessage: 'Hello!' }})
53+
render: h => h(App, { props: { propMessage: 'World!' }})
5954
})

src/component.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import * as Vue from 'vue'
22
import { VueClass } from './declarations'
3+
import { collectDataFromConstructor } from './data'
34

45
const internalHooks = [
56
'data',
@@ -44,6 +45,14 @@ export function componentFactory (
4445
}
4546
}
4647
})
48+
49+
// add data hook to collect class properties as Vue instance's data
50+
;(options.mixins || (options.mixins = [])).push({
51+
data (this: Vue) {
52+
return collectDataFromConstructor(this, Component)
53+
}
54+
})
55+
4756
// find super
4857
const superProto = Object.getPrototypeOf(Component.prototype)
4958
const Super: VueClass = superProto instanceof Vue

src/data.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import * as Vue from 'vue'
2+
import { VueClass } from './declarations'
3+
4+
const noop = () => {}
5+
6+
export function collectDataFromConstructor (vm: Vue, Component: VueClass) {
7+
// Create dummy Vue instance to collect
8+
// initial class properties from the component constructor.
9+
// To prevent to print warning,
10+
// the data object should inherit Vue.prototype.
11+
const data = Object.create(vm, {
12+
_init: {
13+
get: () => noop
14+
}
15+
})
16+
17+
// call constructor with passing dummy instance
18+
// `data` object will have initial data
19+
Component.call(data)
20+
21+
// create plain data object
22+
const plainData = {}
23+
Object.keys(data).forEach(key => {
24+
plainData[key] = data[key]
25+
})
26+
27+
return plainData
28+
}

test/test.ts

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,44 @@ describe('vue-class-component', () => {
2525
expect(destroyed).to.be.true
2626
})
2727

28+
it('data: should collect from class properties', () => {
29+
@Component({
30+
props: ['foo']
31+
})
32+
class MyComp extends Vue {
33+
foo: number
34+
a: string = 'hello'
35+
b: number = this.foo + 1
36+
}
37+
38+
const c = new MyComp({
39+
propsData: {
40+
foo: 1
41+
}
42+
})
43+
expect(c.a).to.equal('hello')
44+
expect(c.b).to.equal(2)
45+
})
46+
47+
it('data: should collect custom property defined on beforeCreate', () => {
48+
@Component
49+
class MyComp extends Vue {
50+
$store: any
51+
foo: string = 'Hello, ' + this.$store.state.msg
52+
53+
beforeCreate () {
54+
this.$store = {
55+
state: {
56+
msg: 'world'
57+
}
58+
}
59+
}
60+
}
61+
62+
const c = new MyComp()
63+
expect(c.foo).to.equal('Hello, world')
64+
})
65+
2866
it('methods', () => {
2967
let msg: string = ''
3068

0 commit comments

Comments
 (0)