Skip to content

Commit 6a66603

Browse files
committed
文档: 完善文档
1 parent c6c68db commit 6a66603

File tree

9 files changed

+718
-593
lines changed

9 files changed

+718
-593
lines changed

docs/index.md

Lines changed: 1 addition & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -13,82 +13,5 @@ features:
1313
details: 无需关注ref及其value,正常声明变量,编程体验更自然
1414
---
1515

16-
#### 以下代码展示常用API
1716

18-
```typescript jsx
19-
import { VueComponent, Ref, Autobind, VueService } from "vue3-oop"
20-
import { Injectable } from "injection-js"
21-
import { createApp, VNodeChild } from "vue"
22-
23-
// 服务,即可复用的逻辑 类似 useXXX
24-
@Injectable()
25-
class CountService extends VueService {
26-
@Ref() count = 0
27-
28-
@Autobind()
29-
add() {
30-
this.count++
31-
}
32-
33-
@Autobind()
34-
remove() {
35-
this.count--
36-
}
37-
}
38-
// 组件
39-
@Component({
40-
providers: [CountService]
41-
})
42-
class Home extends VueComponent {
43-
// 构造函数注入服务,无需new
44-
constructor(private countService: CountService) {
45-
super()
46-
}
47-
48-
render() {
49-
return <div>
50-
<span onClick={this.countService.add}>+</span>
51-
{this.countService.count}
52-
<span onClick={this.countService.remove}>-</span>
53-
</div>
54-
}
55-
}
56-
57-
// 子组件属性
58-
interface HomeChild_Props<DataItem = any> {
59-
list: DataItem[]
60-
title: string | ((list: DataItem[]) => VNodeChild)
61-
['v-slots']?: {
62-
default(): VNodeChild
63-
item(item: DataItem): VNodeChild
64-
}
65-
}
66-
67-
// 子组件
68-
class HomeChild<T> extends VueComponent<HomeChild_Props<T>> {
69-
static defaultProps: ComponentProps<HomeChild_Props> = {
70-
list: {
71-
type: Array,
72-
required: true
73-
},
74-
title: {
75-
type: [String, Function],
76-
required: true
77-
},
78-
}
79-
80-
render() {
81-
return (
82-
<div>
83-
{
84-
85-
}
86-
</div>
87-
);
88-
}
89-
90-
}
91-
92-
const app = createApp(Home)
93-
app.mount('#app')
94-
```
17+
<iframe src="https://stackblitz.com/edit/vite-y7m4fy?embed=1&file=main.tsx" height="600" width="100%" frameborder="0"></iframe>

example/focus.directive.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import { Directive } from 'vue'
2+
3+
export const focusDirective: Directive = {
4+
mounted(el: HTMLInputElement, binding) {
5+
console.log(binding)
6+
el.focus()
7+
},
8+
}

example/main.tsx

Lines changed: 115 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,118 @@
11
import '@abraham/reflection'
2-
import { createApp } from 'vue'
3-
import './theme/app.css'
4-
import 'ant-design-vue/dist/antd.css'
5-
import { App } from './app'
2+
import { Autobind, Component, ComponentProps, Computed, Hook, Link, Ref, VueComponent, VueService } from '@/index'
3+
import { forwardRef, Inject, Injectable, SkipSelf } from 'injection-js'
4+
import { createApp, watch } from 'vue'
65

7-
const app = createApp(App)
6+
// 服务,即可复用的逻辑 类似 useXXX
7+
@Injectable()
8+
class CountService extends VueService {
9+
@Ref() count = 0
10+
11+
@Autobind()
12+
add() {
13+
this.count++
14+
}
15+
16+
@Autobind()
17+
remove() {
18+
this.count--
19+
}
20+
}
21+
22+
// 组件属性声明
23+
interface HomeChild_Props {
24+
size: 'small' | 'large'
25+
}
26+
27+
// 带属性组件
28+
@Component({ providers: [CountService] })
29+
class HomeChild extends VueComponent<HomeChild_Props> {
30+
static defaultProps: ComponentProps<HomeChild_Props> = {
31+
size: String,
32+
}
33+
34+
constructor(
35+
private countService: CountService,
36+
@SkipSelf() private parentCountService: CountService,
37+
@Inject(forwardRef(() => Home)) private parent: InstanceType<typeof Home>,
38+
) {
39+
super()
40+
}
41+
42+
render() {
43+
return (
44+
<div style={{ marginTop: '40px' }}>
45+
<h1>子组件</h1>
46+
<h4>子组件属性是:{this.props.size}</h4>
47+
<h4>父组件外部服务状态: {this.parentCountService.count}</h4>
48+
<h4>父组件内部服务状态: {this.parent.count}</h4>
49+
<h3>子组件内部服务</h3>
50+
<button onClick={this.countService.add}>+</button>
51+
{this.countService.count}
52+
<button onClick={this.countService.remove}>-</button>
53+
</div>
54+
)
55+
}
56+
}
57+
58+
// 组件
59+
@Component({ providers: [CountService] }) // 声明自己的服务
60+
class Home extends VueComponent {
61+
// 构造函数注入服务,无需new
62+
constructor(private countService: CountService) {
63+
super()
64+
watch(
65+
() => countService.count,
66+
() => console.log('数据变化哦'),
67+
)
68+
}
69+
70+
// 组件自身的状态
71+
@Ref() count = 1
72+
73+
// 计算属性
74+
@Computed()
75+
get plusResult() {
76+
return this.count + this.countService.count
77+
}
78+
79+
// 声明周期
80+
@Hook('Mounted')
81+
mounted() {
82+
console.log('mounted', this.child?.props.size)
83+
}
84+
85+
// 子组件引用 链接🔗
86+
@Link() child?: HomeChild
87+
88+
@Autobind()
89+
add() {
90+
this.count++
91+
}
92+
93+
@Autobind()
94+
remove() {
95+
this.count--
96+
}
97+
98+
render() {
99+
return (
100+
<div style={{ textAlign: 'center' }}>
101+
<h2>外部服务</h2>
102+
<button onClick={this.countService.add}>+</button>
103+
{this.countService.count}
104+
<button onClick={this.countService.remove}>-</button>
105+
106+
<h2>组件自身状态</h2>
107+
<button onClick={this.add}>+</button>
108+
{this.count}
109+
<button onClick={this.remove}>-</button>
110+
111+
<HomeChild ref="child" size={'small'}></HomeChild>
112+
</div>
113+
)
114+
}
115+
}
116+
117+
const app = createApp(Home)
8118
app.mount('#app')

example/module/home/home.view.tsx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,15 @@ import { CountService } from '../../count.service'
33
import { Optional, SkipSelf } from 'injection-js'
44
import { Button, Col, Row } from 'ant-design-vue'
55
import { watch } from 'vue'
6+
import { focusDirective } from '../../focus.directive'
67

78
@Component({
89
providers: [CountService],
910
})
1011
export default class HomeView extends VueComponent {
12+
static directives = {
13+
focus: focusDirective,
14+
}
1115
constructor(
1216
@SkipSelf() private parentCountService: CountService,
1317
private countService: CountService,
@@ -36,6 +40,7 @@ export default class HomeView extends VueComponent {
3640
<Button type={'primary'} danger onClick={this.countService.remove}>
3741
3842
</Button>
43+
<input v-focus placeholder={'测试指令'} />
3944
</Col>
4045
</Row>
4146
</>

package.json

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -52,35 +52,35 @@
5252
"license": "MIT",
5353
"devDependencies": {
5454
"@abraham/reflection": "^0.8.0",
55-
"@commitlint/cli": "^13.1.0",
56-
"@types/prettier": "^2.3.2",
55+
"@commitlint/cli": "^15.0.0",
56+
"@types/prettier": "^2.4.2",
5757
"@types/swagger-schema-official": "^2.0.22",
58-
"@typescript-eslint/eslint-plugin": "^4.29.2",
59-
"@typescript-eslint/parser": "^4.29.2",
58+
"@typescript-eslint/eslint-plugin": "^5.5.0",
59+
"@typescript-eslint/parser": "^5.5.0",
6060
"@vitejs/plugin-vue": "^1.9.4",
6161
"ant-design-vue": "^3.0.0-alpha.11",
62+
"autobind-decorator": "^2.4.0",
6263
"axios": "^0.24.0",
6364
"commitizen": "^4.2.4",
6465
"commitlint-config-cz": "^0.13.2",
6566
"conventional-github-releaser": "^3.1.5",
6667
"cz-customizable": "^6.3.0",
67-
"eslint": "^7.32.0",
68+
"eslint": "^8.4.0",
6869
"eslint-config-prettier": "^8.3.0",
69-
"eslint-plugin-prettier": "^3.4.1",
70-
"lint-staged": "^11.1.2",
70+
"eslint-plugin-prettier": "^4.0.0",
71+
"injection-js": "^2.4.0",
72+
"lint-staged": "^12.1.2",
7173
"npm-run-all": "^4.1.5",
72-
"prettier": "^2.3.2",
74+
"prettier": "^2.5.1",
7375
"rimraf": "^3.0.2",
7476
"standard-version": "^9.3.2",
75-
"typescript": "^4.3.5",
76-
"vite": "^2.5.0",
77+
"typescript": "^4.5.2",
78+
"vite": "^2.6.14",
7779
"vite-plugin-ts": "^1.1.8",
7880
"vitepress": "^0.20.1",
79-
"yorkie": "^2.0.0",
80-
"autobind-decorator": "^2.4.0",
81-
"injection-js": "^2.4.0",
8281
"vue": "^3.2.20",
83-
"vue-router": "^4.0.12"
82+
"vue-router": "^4.0.12",
83+
"yorkie": "^2.0.0"
8484
},
8585
"config": {
8686
"commitizen": {

src/extends/component.ts

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,19 @@ import { LinkHandler } from '@/decorators/link'
88

99
export const GlobalStoreKey = 'GlobalStoreKey'
1010

11+
type VueComponentProps<T extends Record<string, any>> = Omit<T, 'slots'> & WithVSlots<T> & VNodeProps
12+
1113
// 处理tsx slots 类型问题
1214
type WithVSlots<T extends Record<string, any>> = 'slots' extends keyof T
13-
? { 'v-slots'?: T['slots'] & { $stable?: boolean } }
14-
: Record<string, never>
15+
? {
16+
'v-slots'?: Partial<T['slots'] & { $stable: boolean; default(): VNodeChild }>
17+
[name: string]: any
18+
}
19+
: Record<string, any>
20+
21+
type WithSlotTypes<T extends Record<string, any>> = Omit<SetupContext, 'slots'> & {
22+
slots: Partial<T['slots'] & { default(): VNodeChild }>
23+
}
1524

1625
export abstract class VueComponent<T = Record<string, any>> {
1726
/** 装饰器处理 */
@@ -52,13 +61,13 @@ export abstract class VueComponent<T = Record<string, any>> {
5261
return this.props
5362
}
5463
/** 组件属性 */
55-
public props: Omit<T, 'slots'> & WithVSlots<T> & VNodeProps & Record<string, any>
64+
public props: VueComponentProps<T>
5665
/** 组件上下文 */
57-
public context: SetupContext
66+
public context: WithSlotTypes<T>
5867

5968
constructor() {
60-
this.props = useProps<Omit<T, 'slots'> & VNodeProps & WithVSlots<T>>()
61-
this.context = useCtx()
69+
this.props = useProps<VueComponentProps<T>>()
70+
this.context = useCtx() as WithSlotTypes<T>
6271
this.context.expose(this)
6372
const ThisConstructor = this.constructor as VueComponentStaticContructor
6473
if (ThisConstructor.ProviderKey) provide(ThisConstructor.ProviderKey, this)
@@ -88,3 +97,9 @@ export abstract class VueComponent<T = Record<string, any>> {
8897
export type ComponentProps<T extends Record<string, any>> = {
8998
[U in keyof Omit<T, 'slots'>]-?: Prop<any>
9099
}
100+
101+
export type ComponentSlots<T extends { props: any }> = T extends { props: infer U }
102+
? 'v-slots' extends keyof U
103+
? U['v-slots']
104+
: Record<string, unknown>
105+
: never

src/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,4 @@ export { Hook } from './decorators/hook'
77
export * from './helper'
88
export { Component, InjectorKey } from './di'
99
export type { ComponentOptions } from './di'
10-
export type { ComponentProps } from './extends/component'
10+
export type { ComponentProps, ComponentSlots } from './extends/component'

tsconfig.json

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,5 +24,13 @@
2424
"@/*": ["src/*"]
2525
}
2626
},
27-
"include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue", "vite.config.ts", "example"]
27+
"include": [
28+
"src/**/*.ts",
29+
"src/**/*.d.ts",
30+
"src/**/*.tsx",
31+
"src/**/*.vue",
32+
"vite.config.ts",
33+
"example/**/*.ts",
34+
"example/**/*.tsx"
35+
]
2836
}

0 commit comments

Comments
 (0)