Skip to content

Commit c574faa

Browse files
authored
refactor(runtime-vapor): simplify directive mechanism (#278)
* feat: custom directive v2 * wip * fix: directive * fix * refactor * refactor: remove ref for el
1 parent eed7d1d commit c574faa

File tree

7 files changed

+153
-156
lines changed

7 files changed

+153
-156
lines changed

packages/runtime-vapor/src/apiCreateFor.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -405,7 +405,7 @@ function getItem(
405405
} else if (typeof source === 'number') {
406406
return [idx + 1, idx, undefined]
407407
} else if (isObject(source)) {
408-
if (source && source[Symbol.iterator as any]) {
408+
if (source[Symbol.iterator as any]) {
409409
source = Array.from(source as Iterable<any>)
410410
return [source[idx], idx, undefined]
411411
} else {

packages/runtime-vapor/src/apiRender.ts

+2-4
Original file line numberDiff line numberDiff line change
@@ -128,15 +128,14 @@ function mountComponent(
128128
}
129129

130130
// hook: beforeMount
131-
invokeLifecycle(instance, VaporLifecycleHooks.BEFORE_MOUNT, 'beforeMount')
131+
invokeLifecycle(instance, VaporLifecycleHooks.BEFORE_MOUNT)
132132

133133
insert(instance.block!, instance.container)
134134

135135
// hook: mounted
136136
invokeLifecycle(
137137
instance,
138138
VaporLifecycleHooks.MOUNTED,
139-
'mounted',
140139
instance => (instance.isMounted = true),
141140
true,
142141
)
@@ -156,7 +155,7 @@ export function unmountComponent(instance: ComponentInternalInstance): void {
156155
const { container, scope } = instance
157156

158157
// hook: beforeUnmount
159-
invokeLifecycle(instance, VaporLifecycleHooks.BEFORE_UNMOUNT, 'beforeUnmount')
158+
invokeLifecycle(instance, VaporLifecycleHooks.BEFORE_UNMOUNT)
160159

161160
scope.stop()
162161
container.textContent = ''
@@ -165,7 +164,6 @@ export function unmountComponent(instance: ComponentInternalInstance): void {
165164
invokeLifecycle(
166165
instance,
167166
VaporLifecycleHooks.UNMOUNTED,
168-
'unmounted',
169167
instance => queuePostFlushCb(() => (instance.isUnmounted = true)),
170168
true,
171169
)

packages/runtime-vapor/src/componentLifecycle.ts

+1-5
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,10 @@ import { invokeArrayFns } from '@vue/shared'
22
import type { VaporLifecycleHooks } from './enums'
33
import { type ComponentInternalInstance, setCurrentInstance } from './component'
44
import { queuePostFlushCb } from './scheduler'
5-
import type { DirectiveHookName } from './directives'
65

76
export function invokeLifecycle(
87
instance: ComponentInternalInstance,
98
lifecycle: VaporLifecycleHooks,
10-
directive: DirectiveHookName,
119
cb?: (instance: ComponentInternalInstance) => void,
1210
post?: boolean,
1311
): void {
@@ -27,8 +25,6 @@ export function invokeLifecycle(
2725
}
2826

2927
function invokeSub() {
30-
instance.comps.forEach(comp =>
31-
invokeLifecycle(comp, lifecycle, directive, cb, post),
32-
)
28+
instance.comps.forEach(comp => invokeLifecycle(comp, lifecycle, cb, post))
3329
}
3430
}
+62-39
Original file line numberDiff line numberDiff line change
@@ -1,54 +1,30 @@
11
import { isBuiltInDirective } from '@vue/shared'
2-
import { type ComponentInternalInstance, currentInstance } from './component'
2+
import {
3+
type ComponentInternalInstance,
4+
currentInstance,
5+
isVaporComponent,
6+
} from './component'
37
import { warn } from './warning'
8+
import { normalizeBlock } from './dom/element'
9+
import { getCurrentScope } from '@vue/reactivity'
10+
import { VaporErrorCodes, callWithAsyncErrorHandling } from './errorHandling'
411

512
export type DirectiveModifiers<M extends string = string> = Record<M, boolean>
613

714
export interface DirectiveBinding<T = any, V = any, M extends string = string> {
815
instance: ComponentInternalInstance
9-
source?: () => V
10-
value: V
11-
oldValue: V | null
16+
source: () => V
1217
arg?: string
1318
modifiers?: DirectiveModifiers<M>
14-
dir: ObjectDirective<T, V, M>
19+
dir: Directive<T, V, M>
1520
}
1621

1722
export type DirectiveBindingsMap = Map<Node, DirectiveBinding[]>
1823

19-
export type DirectiveHook<
20-
T = any | null,
21-
V = any,
22-
M extends string = string,
23-
> = (node: T, binding: DirectiveBinding<T, V, M>) => void
24-
25-
// create node -> `created` -> node operation -> `beforeMount` -> node mounted -> `mounted`
26-
// effect update -> `beforeUpdate` -> node updated -> `updated`
27-
// `beforeUnmount`-> node unmount -> `unmounted`
28-
export type DirectiveHookName =
29-
| 'created'
30-
| 'beforeMount'
31-
| 'mounted'
32-
| 'beforeUpdate'
33-
| 'updated'
34-
| 'beforeUnmount'
35-
| 'unmounted'
36-
export type ObjectDirective<T = any, V = any, M extends string = string> = {
37-
[K in DirectiveHookName]?: DirectiveHook<T, V, M> | undefined
38-
} & {
39-
/** Watch value deeply */
40-
deep?: boolean | number
41-
}
42-
43-
export type FunctionDirective<
44-
T = any,
45-
V = any,
46-
M extends string = string,
47-
> = DirectiveHook<T, V, M>
48-
49-
export type Directive<T = any, V = any, M extends string = string> =
50-
| ObjectDirective<T, V, M>
51-
| FunctionDirective<T, V, M>
24+
export type Directive<T = any, V = any, M extends string = string> = (
25+
node: T,
26+
binding: DirectiveBinding<T, V, M>,
27+
) => void
5228

5329
export function validateDirectiveName(name: string): void {
5430
if (isBuiltInDirective(name)) {
@@ -77,7 +53,54 @@ export function withDirectives<T extends ComponentInternalInstance | Node>(
7753
return nodeOrComponent
7854
}
7955

80-
// NOOP
56+
let node: Node
57+
if (isVaporComponent(nodeOrComponent)) {
58+
const root = getComponentNode(nodeOrComponent)
59+
if (!root) return nodeOrComponent
60+
node = root
61+
} else {
62+
node = nodeOrComponent
63+
}
64+
65+
const instance = currentInstance!
66+
const parentScope = getCurrentScope()
67+
68+
if (__DEV__ && !parentScope) {
69+
warn(`Directives should be used inside of RenderEffectScope.`)
70+
}
71+
72+
for (const directive of directives) {
73+
let [dir, source = () => undefined, arg, modifiers] = directive
74+
if (!dir) continue
75+
76+
const binding: DirectiveBinding = {
77+
dir,
78+
source,
79+
instance,
80+
arg,
81+
modifiers,
82+
}
83+
84+
callWithAsyncErrorHandling(dir, instance, VaporErrorCodes.DIRECTIVE_HOOK, [
85+
node,
86+
binding,
87+
])
88+
}
8189

8290
return nodeOrComponent
8391
}
92+
93+
function getComponentNode(component: ComponentInternalInstance) {
94+
if (!component.block) return
95+
96+
const nodes = normalizeBlock(component.block)
97+
if (nodes.length !== 1) {
98+
warn(
99+
`Runtime directive used on component with non-element root node. ` +
100+
`The directives will not function as intended.`,
101+
)
102+
return
103+
}
104+
105+
return nodes[0]
106+
}

0 commit comments

Comments
 (0)