Skip to content

Commit 0a11308

Browse files
ktsnyyx990803
authored andcommitted
Provide a helper to create custom decorators (#30)
* add create decorator helper * update readme for createDecorator helper
1 parent c14d73e commit 0a11308

File tree

6 files changed

+101
-3
lines changed

6 files changed

+101
-3
lines changed

Diff for: README.md

+34
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,40 @@ class App {
6464

6565
You may also want to check out the `@prop` and `@watch` decorators provided by [vue-property-decorators](https://github.com/kaorun343/vue-property-decorator).
6666

67+
### Create Custom Decorators
68+
69+
You can extend the functionality of this library by creating your own decorators. vue-class-component provides `createDecorator` helper to create custom decorators. `createDecorator` expects a callback function as the 1st argument and the callback will receive following arguments:
70+
71+
- `options`: Vue component options object. Changes for this object will affect the provided component.
72+
- `key`: The property or method key that the decorator is applied.
73+
- `parameterIndex`: The index of a decorated argument if the custom decorator is used for an argument.
74+
75+
Example of creating `NoCache` decorator:
76+
77+
``` js
78+
// decorators.js
79+
import { createDecorator } from 'vue-class-component'
80+
81+
export const NoCache = createDecorator((options, key) => {
82+
// component options should be passed to the callback
83+
// and update for the options object affect the component
84+
options.computed[key].cache = false
85+
})
86+
```
87+
88+
``` js
89+
import { NoCache } from './decorators'
90+
91+
@Component
92+
class MyComp extends Vue {
93+
// the computed property will not be cached
94+
@NoCache
95+
get random () {
96+
return Math.random()
97+
}
98+
}
99+
```
100+
67101
### Build the Example
68102

69103
``` bash

Diff for: src/component.ts

+10
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,11 @@ const internalHooks = [
1717
'render'
1818
]
1919

20+
// Property, method and parameter decorators created by `createDecorator` helper
21+
// will enqueue functions that update component options for lazy processing.
22+
// They will be executed just before creating component constructor.
23+
export let $decoratorQueue: ((options: Vue.ComponentOptions<Vue>) => void)[] = []
24+
2025
export function componentFactory (
2126
Component: VueClass,
2227
options: Vue.ComponentOptions<any> = {}
@@ -53,6 +58,11 @@ export function componentFactory (
5358
}
5459
})
5560

61+
// decorate options
62+
$decoratorQueue.forEach(fn => fn(options))
63+
// reset for other component decoration
64+
$decoratorQueue = []
65+
5666
// find super
5767
const superProto = Object.getPrototypeOf(Component.prototype)
5868
const Super: VueClass = superProto instanceof Vue

Diff for: src/data.ts

+1-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import * as Vue from 'vue'
22
import { VueClass } from './declarations'
3-
4-
const noop = () => {}
3+
import { noop } from './util'
54

65
export function collectDataFromConstructor (vm: Vue, Component: VueClass) {
76
// Create dummy Vue instance to collect

Diff for: src/index.ts

+2
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ import { VueClass } from './declarations'
33

44
import { componentFactory } from './component'
55

6+
export { createDecorator } from './util'
7+
68
export default function Component <U extends Vue>(options: Vue.ComponentOptions<U>): <V extends VueClass>(target: V) => V
79
export default function Component <V extends VueClass>(target: V): V
810
export default function Component <V extends VueClass>(options: Vue.ComponentOptions<any> | V): any {

Diff for: src/util.ts

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import * as Vue from 'vue'
2+
import { $decoratorQueue } from './component'
3+
4+
export const noop = () => {}
5+
6+
export function createDecorator (
7+
factory: (options: Vue.ComponentOptions<Vue>, key: string) => void
8+
): (target: Vue, key: string) => void
9+
export function createDecorator (
10+
factory: (options: Vue.ComponentOptions<Vue>, key: string, index: number) => void
11+
): (target: Vue, key: string, index: number) => void
12+
export function createDecorator (
13+
factory: (options: Vue.ComponentOptions<Vue>, key: string, index: number) => void
14+
): (target: Vue, key: string, index: any) => void {
15+
return (_, key, index) => {
16+
if (typeof index !== 'number') {
17+
index = undefined
18+
}
19+
$decoratorQueue.push(options => factory(options, key, index))
20+
}
21+
}

Diff for: test/test.ts

+33-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import Component from '../lib/index'
1+
import Component, { createDecorator } from '../lib/index'
22
import { expect } from 'chai'
33
import * as Vue from 'vue'
44

@@ -143,4 +143,36 @@ describe('vue-class-component', () => {
143143
expect(a.a).to.equal(1)
144144
expect(a.b).to.equal(2)
145145
})
146+
147+
it('createDecorator', function () {
148+
const Prop = createDecorator((options, key) => {
149+
// component options should be passed to the callback
150+
// and update for the options affect the component
151+
(options.props || (options.props = {}))[key] = true
152+
})
153+
154+
const NoCache = createDecorator((options, key) => {
155+
// options should have computed and methods etc.
156+
// that specified by class property accessors and methods
157+
const computedOption: Vue.ComputedOptions<Vue> = options.computed![key]
158+
computedOption.cache = false
159+
})
160+
161+
@Component
162+
class MyComp extends Vue {
163+
@Prop foo: string
164+
@NoCache get bar (): string {
165+
return 'world'
166+
}
167+
}
168+
169+
const c = new MyComp({
170+
propsData: {
171+
foo: 'hello'
172+
}
173+
})
174+
expect(c.foo).to.equal('hello')
175+
expect(c.bar).to.equal('world')
176+
expect((MyComp as any).options.computed.bar.cache).to.be.false
177+
})
146178
})

0 commit comments

Comments
 (0)