2024-03-16 18:54:36 +08:00
|
|
|
import { type Block, type Fragment, fragmentKey } from './apiRender'
|
2024-05-27 02:47:51 +08:00
|
|
|
import { getCurrentScope } from '@vue/reactivity'
|
2024-02-26 21:38:04 +08:00
|
|
|
import { createComment, createTextNode, insert, remove } from './dom/element'
|
2024-05-27 02:47:51 +08:00
|
|
|
import { currentInstance } from './component'
|
|
|
|
import { warn } from './warning'
|
|
|
|
import { BlockEffectScope, isRenderEffectScope } from './blockEffectScope'
|
|
|
|
import {
|
|
|
|
createChildFragmentDirectives,
|
|
|
|
invokeWithMount,
|
|
|
|
invokeWithUnmount,
|
|
|
|
invokeWithUpdate,
|
|
|
|
} from './directivesChildFragment'
|
2024-01-19 16:38:41 +08:00
|
|
|
|
2024-01-30 04:15:52 +08:00
|
|
|
type BlockFn = () => Block
|
|
|
|
|
2024-02-08 23:22:03 +08:00
|
|
|
/*! #__NO_SIDE_EFFECTS__ */
|
2024-01-19 16:38:41 +08:00
|
|
|
export const createIf = (
|
|
|
|
condition: () => any,
|
|
|
|
b1: BlockFn,
|
|
|
|
b2?: BlockFn,
|
2024-05-12 18:20:14 +08:00
|
|
|
once?: boolean,
|
2024-01-19 16:38:41 +08:00
|
|
|
// hydrationNode?: Node,
|
|
|
|
): Fragment => {
|
2024-03-18 20:13:40 +08:00
|
|
|
let newValue: any
|
|
|
|
let oldValue: any
|
2024-01-19 16:38:41 +08:00
|
|
|
let branch: BlockFn | undefined
|
|
|
|
let parent: ParentNode | undefined | null
|
2024-01-30 04:15:52 +08:00
|
|
|
let block: Block | undefined
|
2024-05-27 02:47:51 +08:00
|
|
|
let scope: BlockEffectScope | undefined
|
|
|
|
const parentScope = getCurrentScope()!
|
2024-01-31 13:16:03 +08:00
|
|
|
const anchor = __DEV__ ? createComment('if') : createTextNode()
|
2024-01-30 04:15:52 +08:00
|
|
|
const fragment: Fragment = {
|
|
|
|
nodes: [],
|
|
|
|
anchor,
|
|
|
|
[fragmentKey]: true,
|
|
|
|
}
|
2024-01-19 16:38:41 +08:00
|
|
|
|
2024-05-27 02:47:51 +08:00
|
|
|
const instance = currentInstance!
|
|
|
|
if (__DEV__ && (!instance || !isRenderEffectScope(parentScope))) {
|
|
|
|
warn('createIf() can only be used inside setup()')
|
|
|
|
}
|
|
|
|
|
2024-01-19 16:38:41 +08:00
|
|
|
// TODO: SSR
|
|
|
|
// if (isHydrating) {
|
|
|
|
// parent = hydrationNode!.parentNode
|
|
|
|
// setCurrentHydrationNode(hydrationNode!)
|
|
|
|
// }
|
|
|
|
|
2024-05-27 02:47:51 +08:00
|
|
|
createChildFragmentDirectives(
|
|
|
|
anchor,
|
|
|
|
() => (scope ? [scope] : []),
|
|
|
|
// source getter
|
|
|
|
condition,
|
|
|
|
// init cb
|
|
|
|
getValue => {
|
|
|
|
newValue = !!getValue()
|
|
|
|
doIf()
|
|
|
|
},
|
|
|
|
// effect cb
|
|
|
|
getValue => {
|
|
|
|
if ((newValue = !!getValue()) !== oldValue) {
|
|
|
|
doIf()
|
|
|
|
} else if (scope) {
|
|
|
|
invokeWithUpdate(scope)
|
2024-01-19 16:38:41 +08:00
|
|
|
}
|
2024-05-27 02:47:51 +08:00
|
|
|
},
|
|
|
|
once,
|
|
|
|
)
|
2024-01-19 16:38:41 +08:00
|
|
|
|
|
|
|
// TODO: SSR
|
|
|
|
// if (isHydrating) {
|
|
|
|
// parent!.insertBefore(anchor, currentHydrationNode)
|
|
|
|
// }
|
|
|
|
|
|
|
|
return fragment
|
2024-05-27 02:47:51 +08:00
|
|
|
|
|
|
|
function doIf() {
|
|
|
|
parent ||= anchor.parentNode
|
|
|
|
if (block) {
|
|
|
|
invokeWithUnmount(scope!, () => remove(block!, parent!))
|
|
|
|
}
|
|
|
|
if ((branch = (oldValue = newValue) ? b1 : b2)) {
|
|
|
|
scope = new BlockEffectScope(instance, parentScope)
|
|
|
|
fragment.nodes = block = scope.run(branch)!
|
|
|
|
invokeWithMount(scope, () => parent && insert(block!, parent, anchor))
|
|
|
|
} else {
|
|
|
|
scope = block = undefined
|
|
|
|
fragment.nodes = []
|
|
|
|
}
|
|
|
|
}
|
2024-01-19 16:38:41 +08:00
|
|
|
}
|