vue3-core/packages/runtime-vapor/src/render.ts

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

117 lines
3.0 KiB
TypeScript
Raw Normal View History

2023-12-26 23:48:45 +08:00
import { proxyRefs } from '@vue/reactivity'
import { type Data, invokeArrayFns, isArray, isObject } from '@vue/shared'
2023-11-17 03:01:19 +08:00
import {
type Component,
2023-12-06 14:59:11 +08:00
type ComponentInternalInstance,
2023-12-03 18:36:01 +08:00
createComponentInstance,
setCurrentInstance,
2023-12-04 16:08:15 +08:00
unsetCurrentInstance,
2023-12-03 18:36:01 +08:00
} from './component'
import { initProps } from './componentProps'
2023-12-08 17:34:33 +08:00
import { invokeDirectiveHook } from './directive'
2024-01-28 20:15:41 +08:00
import { insert, querySelector, remove } from './dom'
2024-01-20 23:48:10 +08:00
import { queuePostRenderEffect } from './scheduler'
2023-11-17 03:01:19 +08:00
2024-01-28 20:15:41 +08:00
export const fragmentKey = Symbol('fragment')
2023-11-17 03:01:19 +08:00
export type Block = Node | Fragment | Block[]
export type ParentBlock = ParentNode | Block[]
2024-01-28 20:15:41 +08:00
export type Fragment = {
nodes: Block
anchor?: Node
[fragmentKey]: true
}
2023-11-17 03:01:19 +08:00
export function render(
comp: Component,
props: Data,
2023-12-01 01:28:16 +08:00
container: string | ParentNode,
): ComponentInternalInstance {
const instance = createComponentInstance(comp)
initProps(instance, props)
return mountComponent(instance, (container = normalizeContainer(container)))
2023-11-17 03:01:19 +08:00
}
export function normalizeContainer(container: string | ParentNode): ParentNode {
return typeof container === 'string'
2024-01-28 20:15:41 +08:00
? (querySelector(container) as ParentNode)
2023-11-17 03:01:19 +08:00
: container
}
2023-12-06 14:59:11 +08:00
export function mountComponent(
instance: ComponentInternalInstance,
2023-12-01 01:28:16 +08:00
container: ParentNode,
2023-12-06 14:59:11 +08:00
) {
instance.container = container
2023-12-04 16:08:15 +08:00
const reset = setCurrentInstance(instance)
2023-12-06 14:59:11 +08:00
const block = instance.scope.run(() => {
const { component, props } = instance
2023-12-06 14:59:11 +08:00
const ctx = { expose: () => {} }
const setupFn =
typeof component === 'function' ? component : component.setup
const stateOrNode = setupFn && setupFn(props, ctx)
let block: Block | undefined
2024-01-28 20:15:41 +08:00
if (
stateOrNode &&
(stateOrNode instanceof Node ||
isArray(stateOrNode) ||
(stateOrNode as any)[fragmentKey])
) {
block = stateOrNode as Block
} else if (isObject(stateOrNode)) {
2024-01-20 20:22:06 +08:00
instance.setupState = proxyRefs(stateOrNode)
}
if (!block && component.render) {
2024-01-20 20:22:06 +08:00
block = component.render(instance.setupState)
2023-12-06 14:59:11 +08:00
}
2023-12-15 01:30:26 +08:00
if (block instanceof DocumentFragment) {
block = Array.from(block.childNodes)
}
if (!block) {
// TODO: warn no template
block = []
}
return (instance.block = block)
2023-12-06 14:59:11 +08:00
})!
const { bm, m } = instance
// hook: beforeMount
bm && invokeArrayFns(bm)
2023-12-04 16:08:15 +08:00
invokeDirectiveHook(instance, 'beforeMount')
insert(block, instance.container)
instance.isMounted = true
// hook: mounted
2024-01-20 23:48:10 +08:00
queuePostRenderEffect(() => {
invokeDirectiveHook(instance, 'mounted')
m && invokeArrayFns(m)
})
reset()
2023-12-04 16:08:15 +08:00
return instance
}
2023-12-06 14:59:11 +08:00
export function unmountComponent(instance: ComponentInternalInstance) {
const { container, block, scope, um, bum } = instance
2023-12-04 16:08:15 +08:00
// hook: beforeUnmount
bum && invokeArrayFns(bum)
2023-12-04 16:08:15 +08:00
invokeDirectiveHook(instance, 'beforeUnmount')
scope.stop()
block && remove(block, container)
instance.isMounted = false
instance.isUnmounted = true
// hook: unmounted
2023-12-04 16:08:15 +08:00
invokeDirectiveHook(instance, 'unmounted')
um && invokeArrayFns(um)
2023-12-04 16:08:15 +08:00
unsetCurrentInstance()
}