Skip to content

Commit 13cafd4

Browse files
committed
feat: 增加useForwardRef
1 parent 937dfef commit 13cafd4

File tree

4 files changed

+103
-13
lines changed

4 files changed

+103
-13
lines changed
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,53 @@
1-
import { Mut, VueComponent } from 'vue3-oop'
1+
import { Hook, Link, useForwardRef, VueComponent } from 'vue3-oop'
2+
import { Input, type InputProps } from 'ant-design-vue'
3+
import { ref } from 'vue'
4+
5+
function createBigSizeInput(size: 'small' | 'middle' | 'large') {
6+
class BigInput extends VueComponent<Omit<InputProps, 'size'>> {
7+
forwardRef = useForwardRef()
8+
9+
render() {
10+
return (
11+
<Input
12+
{...this.context.attrs}
13+
ref={this.forwardRef}
14+
size={size}
15+
></Input>
16+
)
17+
}
18+
}
19+
return BigInput
20+
}
21+
22+
const BigInput = createBigSizeInput('large')
23+
24+
class Abc extends VueComponent {
25+
a = ref(0)
26+
27+
render() {
28+
return <div>{this.a.value}</div>
29+
}
30+
}
231

332
export default class HelloWorldView extends VueComponent {
4-
@Mut() msg = 'hello world'
33+
@Link() abc: Abc[]
34+
35+
@Link() input: any
36+
37+
@Hook('Mounted')
38+
mounted() {
39+
console.log(this.abc)
40+
console.log(this.input)
41+
}
542
render() {
6-
return <h1>{this.msg}</h1>
43+
return (
44+
<div>
45+
<button onClick={() => this.abc}>+</button>
46+
<Abc ref_for ref_key={'abc'} ref={'abc'}></Abc>
47+
<Abc ref_for ref_key={'abc'} ref={'abc'}></Abc>
48+
<Abc ref_for ref_key={'abc'} ref={'abc'}></Abc>
49+
<BigInput ref={'input'}></BigInput>
50+
</div>
51+
)
752
}
853
}

example/router/routes.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ export const routes: RouteRecordRaw[] = [
1212
children: [
1313
{
1414
path: '/basic/hello-world',
15-
component: () => import('../module/basic/hello-world/hello.vue'),
15+
component: () => import('../module/basic/hello-world/hello-world.view'),
1616
meta: {
1717
title: 'Hello Wolrd',
1818
},

src/extends/component.ts

+49-8
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ type VueComponentProps<T extends {}> = Omit<T, 'slots'> &
3030
AllowedComponentProps &
3131
Record<string, unknown>
3232

33+
// @ts-ignore
3334
export abstract class VueComponent<T extends {} = {}> {
3435
/** 热更新使用 */
3536
static __hmrId?: string
@@ -49,25 +50,54 @@ export abstract class VueComponent<T extends {} = {}> {
4950
static globalStore?: boolean
5051
/** 是否把自己当做服务provide出去,以便子组件可注入 */
5152
static ProviderKey?: string | symbol | number | InjectionKey<any>
52-
/** 主要给jsx提示用 */
53-
get $props() {
54-
return this.props
55-
}
5653
/** 组件属性 */
5754
public props = useProps<VueComponentProps<T>>()
5855
/** 组件上下文 */
5956
public context = useCtx() as WithSlotTypes<T>
6057
/** 组件内部实例,如果使用组件实例请 this.$.proxy */
6158
public $ = getCurrentInstance()!
59+
/** 主要给jsx提示用 */
60+
get $props() {
61+
return this.props
62+
}
63+
get $el() {
64+
return this.$.proxy?.$el
65+
}
66+
get $refs() {
67+
return this.$.proxy?.$refs
68+
}
69+
get $parent() {
70+
return this.$.proxy?.$parent
71+
}
72+
get $root() {
73+
return this.$.proxy?.$root
74+
}
75+
get $emit() {
76+
return this.$.proxy?.$emit
77+
}
78+
get $forceUpdate() {
79+
return this.$.proxy?.$forceUpdate
80+
}
81+
get $nextTick() {
82+
return this.$.proxy?.$nextTick
83+
}
84+
get $watch() {
85+
return this.$.proxy?.$watch
86+
}
6287

6388
constructor() {
64-
this.context.expose(this)
89+
markRaw(this)
90+
// 处理ref
91+
const current = this.$
92+
// 由于vue会包装一层,会自动代理ref,导致类型错误, 还导致不能修改变量
93+
current.exposed = this
94+
current.exposeProxy = this
95+
96+
// 处理依赖注入
6597
const ThisConstructor = this.constructor as VueComponentStaticContructor
6698
if (ThisConstructor.ProviderKey) provide(ThisConstructor.ProviderKey, this)
6799
if (ThisConstructor.globalStore) {
68100
// 如果作为全局的服务,则注入到根上面
69-
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
70-
const current = getCurrentInstance()!
71101
const app = current.appContext.app
72102
app.provide(GlobalStoreKey, this)
73103
app.getStore = () => this
@@ -82,13 +112,14 @@ export abstract class VueComponent<T extends {} = {}> {
82112
return current?.provides[token]
83113
}
84114
}
115+
85116
VueComponent.handler.forEach((handler) => handler.handler(this))
86117
}
87118

88119
/** 渲染函数 */
89120
render?(ctx: ComponentPublicInstance, cache: any[]): VNodeChild
90121
}
91-
// 为了支持es5浏览器
122+
// 某些浏览器不支持 static get
92123
Object.defineProperty(VueComponent, '__vccOpts', {
93124
enumerable: true,
94125
configurable: true,
@@ -123,3 +154,13 @@ Object.defineProperty(VueComponent, '__vccOpts', {
123154
})
124155
},
125156
})
157+
158+
// 处理forwardref
159+
export function useForwardRef() {
160+
const instance = getCurrentInstance()!
161+
function forwardRef(ref: any) {
162+
instance.exposed = ref
163+
instance.exposeProxy = ref
164+
}
165+
return forwardRef
166+
}

src/index.ts

+5-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
1-
export { VueComponent, GlobalStoreKey } from './extends/component'
1+
export {
2+
VueComponent,
3+
GlobalStoreKey,
4+
useForwardRef,
5+
} from './extends/component'
26
export { VueService, ProviderKey } from './extends/service'
37
export { Mut } from './decorators/mut'
48
export { Computed } from './decorators/computed'

0 commit comments

Comments
 (0)