-
-
Notifications
You must be signed in to change notification settings - Fork 100
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
af9f892
commit 8b504c8
Showing
9 changed files
with
212 additions
and
20 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
import { defineComponent } from 'vue' | ||
import { | ||
children, | ||
createIf, | ||
insert, | ||
nextTick, | ||
ref, | ||
render, | ||
renderEffect, | ||
setText, | ||
template, | ||
} from '../src' | ||
import { NOOP } from '@vue/shared' | ||
import type { Mock } from 'vitest' | ||
|
||
let host: HTMLElement | ||
|
||
const initHost = () => { | ||
host = document.createElement('div') | ||
host.setAttribute('id', 'host') | ||
document.body.appendChild(host) | ||
} | ||
beforeEach(() => { | ||
initHost() | ||
}) | ||
afterEach(() => { | ||
host.remove() | ||
}) | ||
|
||
describe('createIf', () => { | ||
test('basic', async () => { | ||
// mock this template: | ||
// <div> | ||
// <p v-if="counter">{{counter}}</p> | ||
// <p v-else>zero</p> | ||
// </div> | ||
|
||
let spyIfFn: Mock<any, any> | ||
let spyElseFn: Mock<any, any> | ||
|
||
let add = NOOP | ||
let reset = NOOP | ||
|
||
// templates can be reused through caching. | ||
const t0 = template('<div></div>') | ||
const t1 = template('<p></p>') | ||
const t2 = template('<p>zero</p>') | ||
|
||
const component = defineComponent({ | ||
setup() { | ||
const counter = ref(0) | ||
add = () => counter.value++ | ||
reset = () => (counter.value = 0) | ||
|
||
// render | ||
return (() => { | ||
const n0 = t0() | ||
const { | ||
0: [n1], | ||
} = children(n0) | ||
|
||
insert( | ||
createIf( | ||
() => counter.value, | ||
// v-if | ||
(spyIfFn ||= vi.fn(() => { | ||
const n2 = t1() | ||
const { | ||
0: [n3], | ||
} = children(n2) | ||
renderEffect(() => { | ||
setText(n3, void 0, counter.value) | ||
}) | ||
return n2 | ||
})), | ||
// v-else | ||
(spyElseFn ||= vi.fn(() => { | ||
const n4 = t2() | ||
return n4 | ||
})), | ||
), | ||
n1, | ||
) | ||
return n0 | ||
})() | ||
}, | ||
}) | ||
render(component as any, {}, '#host') | ||
|
||
expect(host.innerHTML).toBe('<div><p>zero</p><!--if--></div>') | ||
expect(spyIfFn!).toHaveBeenCalledTimes(0) | ||
expect(spyElseFn!).toHaveBeenCalledTimes(1) | ||
|
||
add() | ||
await nextTick() | ||
expect(host.innerHTML).toBe('<div><p>1</p><!--if--></div>') | ||
expect(spyIfFn!).toHaveBeenCalledTimes(1) | ||
expect(spyElseFn!).toHaveBeenCalledTimes(1) | ||
|
||
add() | ||
await nextTick() | ||
expect(host.innerHTML).toBe('<div><p>2</p><!--if--></div>') | ||
expect(spyIfFn!).toHaveBeenCalledTimes(1) | ||
expect(spyElseFn!).toHaveBeenCalledTimes(1) | ||
|
||
reset() | ||
await nextTick() | ||
expect(host.innerHTML).toBe('<div><p>zero</p><!--if--></div>') | ||
expect(spyIfFn!).toHaveBeenCalledTimes(1) | ||
expect(spyElseFn!).toHaveBeenCalledTimes(2) | ||
}) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
import { renderWatch } from './renderWatch' | ||
import type { BlockFn, Fragment } from './render' | ||
import { effectScope, onEffectCleanup } from '@vue/reactivity' | ||
import { insert, remove } from './dom' | ||
|
||
export const createIf = ( | ||
condition: () => any, | ||
b1: BlockFn, | ||
// 如果是 v-else-if 就把 () => createIf 作为 b2 传入 | ||
b2?: BlockFn, | ||
hydrationNode?: Node, | ||
): Fragment => { | ||
let branch: BlockFn | undefined | ||
let parent: ParentNode | undefined | null | ||
const anchor = __DEV__ | ||
? // eslint-disable-next-line no-restricted-globals | ||
document.createComment('if') | ||
: // eslint-disable-next-line no-restricted-globals | ||
document.createTextNode('') | ||
const fragment: Fragment = { nodes: [], anchor } | ||
|
||
// TODO: SSR | ||
// if (isHydrating) { | ||
// parent = hydrationNode!.parentNode | ||
// setCurrentHydrationNode(hydrationNode!) | ||
// } | ||
|
||
renderWatch( | ||
() => Boolean(condition()), | ||
(value) => { | ||
parent ||= anchor.parentNode | ||
if ((branch = value ? b1 : b2)) { | ||
let scope = effectScope() | ||
let block = scope.run(branch)! | ||
|
||
if (block instanceof DocumentFragment) { | ||
block = Array.from(block.childNodes) | ||
} | ||
fragment.nodes = block | ||
|
||
parent && insert(block, parent, anchor) | ||
|
||
onEffectCleanup(() => { | ||
parent ||= anchor.parentNode | ||
scope.stop() | ||
remove(block, parent!) | ||
}) | ||
} else { | ||
fragment.nodes = [] | ||
} | ||
}, | ||
{ immediate: true }, | ||
) | ||
|
||
// TODO: SSR | ||
// if (isHydrating) { | ||
// parent!.insertBefore(anchor, currentHydrationNode) | ||
// } | ||
|
||
return fragment | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters