2023-12-10 01:33:18 +08:00
|
|
|
import { markRaw, proxyRefs } from '@vue/reactivity'
|
|
|
|
import { type Data } from '@vue/shared'
|
2023-11-17 03:01:19 +08:00
|
|
|
import {
|
2023-12-10 01:33:18 +08:00
|
|
|
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'
|
2023-12-10 01:33:18 +08:00
|
|
|
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'
|
2023-12-10 01:33:18 +08:00
|
|
|
import { PublicInstanceProxyHandlers } from './componentPublicInstance'
|
2023-11-17 03:01:19 +08:00
|
|
|
|
|
|
|
export type Block = Node | Fragment | Block[]
|
2023-11-27 05:28:50 +08:00
|
|
|
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(
|
2023-12-10 01:33:18 +08:00
|
|
|
comp: Component,
|
|
|
|
props: Data,
|
2023-12-01 01:28:16 +08:00
|
|
|
container: string | ParentNode,
|
2023-11-30 02:11:21 +08:00
|
|
|
): ComponentInternalInstance {
|
|
|
|
const instance = createComponentInstance(comp)
|
2023-12-10 01:33:18 +08:00
|
|
|
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(
|
2023-11-30 02:11:21 +08:00
|
|
|
instance: ComponentInternalInstance,
|
2023-12-01 01:28:16 +08:00
|
|
|
container: ParentNode,
|
2023-12-06 14:59:11 +08:00
|
|
|
) {
|
2023-11-30 02:11:21 +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(() => {
|
2023-12-10 01:33:18 +08:00
|
|
|
const { component, props } = instance
|
2023-12-06 14:59:11 +08:00
|
|
|
const ctx = { expose: () => {} }
|
|
|
|
|
|
|
|
const setupFn =
|
|
|
|
typeof component === 'function' ? component : component.setup
|
2023-12-10 01:33:18 +08:00
|
|
|
instance.proxy = markRaw(
|
|
|
|
new Proxy({ _: instance }, PublicInstanceProxyHandlers),
|
|
|
|
)
|
2023-12-13 15:16:33 +08:00
|
|
|
const state = setupFn && setupFn(props, ctx)
|
2023-12-15 01:23:17 +08:00
|
|
|
let block: Block | null = null
|
2023-12-06 14:59:11 +08:00
|
|
|
if (state && '__isScriptSetup' in state) {
|
2023-12-10 01:33:18 +08:00
|
|
|
instance.setupState = proxyRefs(state)
|
2023-12-15 01:23:17 +08:00
|
|
|
block = component.render(instance.proxy)
|
2023-12-06 14:59:11 +08:00
|
|
|
} else {
|
2023-12-15 01:23:17 +08:00
|
|
|
block = state as Block
|
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)
|
|
|
|
}
|
2023-12-15 01:23:17 +08:00
|
|
|
return (instance.block = block)
|
2023-12-06 14:59:11 +08:00
|
|
|
})!
|
2023-12-04 16:08:15 +08:00
|
|
|
invokeDirectiveHook(instance, 'beforeMount')
|
2023-11-30 02:11:21 +08:00
|
|
|
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')
|
2023-12-10 01:33:18 +08:00
|
|
|
unsetCurrentInstance()
|
2023-12-04 16:08:15 +08:00
|
|
|
|
2023-11-30 02:11:21 +08:00
|
|
|
// TODO: lifecycle hooks (mounted, ...)
|
|
|
|
// const { m } = instance
|
|
|
|
// m && invoke(m)
|
2023-12-10 01:33:18 +08:00
|
|
|
|
|
|
|
return instance
|
2023-11-30 02:11:21 +08:00
|
|
|
}
|
|
|
|
|
2023-12-06 14:59:11 +08:00
|
|
|
export function unmountComponent(instance: ComponentInternalInstance) {
|
2023-11-30 02:11:21 +08:00
|
|
|
const { container, block, scope } = instance
|
2023-12-04 16:08:15 +08:00
|
|
|
|
|
|
|
invokeDirectiveHook(instance, 'beforeUnmount')
|
2023-11-30 02:11:21 +08:00
|
|
|
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()
|
|
|
|
|
2023-11-30 02:11:21 +08:00
|
|
|
// TODO: lifecycle hooks (unmounted, ...)
|
|
|
|
// const { um } = instance
|
|
|
|
// um && invoke(um)
|
|
|
|
}
|