2023-12-26 23:48:45 +08:00
|
|
|
import { proxyRefs } from '@vue/reactivity'
|
2024-01-19 22:43:43 +08:00
|
|
|
import { type Data, invokeArrayFns, isArray, isObject } 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-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 }
|
2024-01-19 16:38:41 +08:00
|
|
|
export type BlockFn = (props?: 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'
|
2023-12-29 22:05:33 +08:00
|
|
|
? // eslint-disable-next-line no-restricted-globals
|
|
|
|
(document.querySelector(container) as ParentNode)
|
2023-11-17 03:01:19 +08:00
|
|
|
: 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
|
|
|
|
2024-01-19 16:38:41 +08:00
|
|
|
const reset = 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
|
2024-01-19 22:43:43 +08:00
|
|
|
const stateOrNode = setupFn && setupFn(props, ctx)
|
|
|
|
|
|
|
|
let block: Block | undefined
|
|
|
|
let setupState: Data | undefined
|
|
|
|
|
|
|
|
if (stateOrNode instanceof Node) {
|
|
|
|
block = stateOrNode
|
|
|
|
} else if (isObject(stateOrNode) && !isArray(stateOrNode)) {
|
|
|
|
setupState = proxyRefs(stateOrNode)
|
|
|
|
}
|
|
|
|
if (!block && component.render) {
|
|
|
|
block = component.render(setupState)
|
2023-12-06 14:59:11 +08:00
|
|
|
}
|
2024-01-19 22:43:43 +08:00
|
|
|
|
2023-12-15 01:30:26 +08:00
|
|
|
if (block instanceof DocumentFragment) {
|
|
|
|
block = Array.from(block.childNodes)
|
|
|
|
}
|
2024-01-19 22:43:43 +08:00
|
|
|
if (!block) {
|
|
|
|
// TODO: warn no template
|
|
|
|
block = []
|
|
|
|
}
|
2023-12-15 01:23:17 +08:00
|
|
|
return (instance.block = block)
|
2023-12-06 14:59:11 +08:00
|
|
|
})!
|
2023-12-15 01:47:56 +08:00
|
|
|
const { bm, m } = instance
|
|
|
|
|
|
|
|
// hook: beforeMount
|
|
|
|
bm && invokeArrayFns(bm)
|
2023-12-04 16:08:15 +08:00
|
|
|
invokeDirectiveHook(instance, 'beforeMount')
|
2023-12-15 01:47:56 +08:00
|
|
|
|
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-15 01:47:56 +08:00
|
|
|
|
|
|
|
// hook: mounted
|
2023-12-04 16:08:15 +08:00
|
|
|
invokeDirectiveHook(instance, 'mounted')
|
2023-12-15 01:47:56 +08:00
|
|
|
m && invokeArrayFns(m)
|
2024-01-19 16:38:41 +08:00
|
|
|
reset()
|
2023-12-04 16:08:15 +08:00
|
|
|
|
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-12-15 01:47:56 +08:00
|
|
|
const { container, block, scope, um, bum } = instance
|
2023-12-04 16:08:15 +08:00
|
|
|
|
2023-12-15 01:47:56 +08:00
|
|
|
// hook: beforeUnmount
|
|
|
|
bum && invokeArrayFns(bum)
|
2023-12-04 16:08:15 +08:00
|
|
|
invokeDirectiveHook(instance, 'beforeUnmount')
|
2023-12-15 01:47:56 +08:00
|
|
|
|
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-15 01:47:56 +08:00
|
|
|
instance.isUnmountedRef.value = true
|
|
|
|
|
|
|
|
// hook: unmounted
|
2023-12-04 16:08:15 +08:00
|
|
|
invokeDirectiveHook(instance, 'unmounted')
|
2023-12-15 01:47:56 +08:00
|
|
|
um && invokeArrayFns(um)
|
2023-12-04 16:08:15 +08:00
|
|
|
unsetCurrentInstance()
|
2023-11-30 02:11:21 +08:00
|
|
|
}
|