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

94 lines
2.7 KiB
TypeScript
Raw Normal View History

import { markRaw, proxyRefs } from '@vue/reactivity'
import { type Data } 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'
2023-12-06 14:59:11 +08:00
import { insert, remove } from './dom'
import { PublicInstanceProxyHandlers } from './componentPublicInstance'
2023-11-17 03:01:19 +08:00
export type Block = Node | Fragment | Block[]
export type ParentBlock = ParentNode | Node[]
2023-11-26 02:13:59 +08:00
export type Fragment = { nodes: Block; anchor: Node }
2023-12-06 14:59:11 +08:00
export type BlockFn = (props: any, ctx: any) => Block
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'
? (document.querySelector(container) as ParentNode)
: 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
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
instance.proxy = markRaw(
new Proxy({ _: instance }, PublicInstanceProxyHandlers),
)
const state = setupFn && setupFn(props, ctx)
let block: Block | null = null
2023-12-06 14:59:11 +08:00
if (state && '__isScriptSetup' in state) {
instance.setupState = proxyRefs(state)
block = component.render(instance.proxy)
2023-12-06 14:59:11 +08:00
} else {
block = state as Block
2023-12-06 14:59:11 +08:00
}
if (block instanceof DocumentFragment) block = Array.from(block.childNodes)
return (instance.block = block)
2023-12-06 14:59:11 +08:00
})!
2023-12-04 16:08:15 +08:00
invokeDirectiveHook(instance, 'beforeMount')
insert(block, instance.container)
2023-12-08 17:34:33 +08:00
instance.isMountedRef.value = true
2023-12-04 16:08:15 +08:00
invokeDirectiveHook(instance, 'mounted')
unsetCurrentInstance()
2023-12-04 16:08:15 +08:00
// TODO: lifecycle hooks (mounted, ...)
// const { m } = instance
// m && invoke(m)
return instance
}
2023-12-06 14:59:11 +08:00
export function unmountComponent(instance: ComponentInternalInstance) {
const { container, block, scope } = instance
2023-12-04 16:08:15 +08:00
invokeDirectiveHook(instance, 'beforeUnmount')
scope.stop()
block && remove(block, container)
2023-12-08 17:34:33 +08:00
instance.isMountedRef.value = false
2023-12-04 16:08:15 +08:00
invokeDirectiveHook(instance, 'unmounted')
unsetCurrentInstance()
// TODO: lifecycle hooks (unmounted, ...)
// const { um } = instance
// um && invoke(um)
}