From: 白雾三语 <32354856+baiwusanyu-c@users.noreply.github.com> Date: Thu, 14 Dec 2023 17:23:17 +0000 (+0800) Subject: fix(runtime-vapor): `unmountComponent` (#63) X-Git-Tag: v3.6.0-alpha.1~16^2~707 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=6eaf4b651b10da9524ad1e05886e37f100e38002;p=thirdparty%2Fvuejs%2Fcore.git fix(runtime-vapor): `unmountComponent` (#63) Co-authored-by: 三咲智子 Kevin Deng --- diff --git a/packages/runtime-vapor/__tests__/component.spec.ts b/packages/runtime-vapor/__tests__/component.spec.ts new file mode 100644 index 0000000000..0d9b26f7a9 --- /dev/null +++ b/packages/runtime-vapor/__tests__/component.spec.ts @@ -0,0 +1,50 @@ +import { + template, + children, + effect, + setText, + render, + getCurrentInstance, + ref, + unmountComponent, +} from '../src' +import type { ComponentInternalInstance } from '../src' +import { afterEach, beforeEach, describe, expect } from 'vitest' +import { defineComponent, nextTick } from '@vue/runtime-core' + +let host: HTMLElement + +const initHost = () => { + host = document.createElement('div') + host.setAttribute('id', 'host') + document.body.appendChild(host) +} +beforeEach(() => { + initHost() +}) +afterEach(() => { + host.remove() +}) +describe('component', () => { + test('unmountComponent', async () => { + const Comp = defineComponent({ + setup() { + const count = ref(0) + const t0 = template('
') + const n0 = t0() + const { + 0: [n1], + } = children(n0) + effect(() => { + setText(n1, void 0, count.value) + }) + return n0 + }, + }) + const instance = render(Comp as any, {}, '#host') + await nextTick() + expect(host.innerHTML).toBe('
0
') + unmountComponent(instance) + expect(host.innerHTML).toBe('') + }) +}) diff --git a/packages/runtime-vapor/src/dom.ts b/packages/runtime-vapor/src/dom.ts index 92bc1e2526..d102433e3a 100644 --- a/packages/runtime-vapor/src/dom.ts +++ b/packages/runtime-vapor/src/dom.ts @@ -42,7 +42,9 @@ export function append(parent: ParentBlock, ...nodes: Node[]) { } export function remove(block: Block, parent: ParentNode) { - if (block instanceof Node) { + if (block instanceof DocumentFragment) { + remove(Array.from(block.childNodes), parent) + } else if (block instanceof Node) { parent.removeChild(block) } else if (isArray(block)) { for (const child of block) remove(child, parent) @@ -52,7 +54,7 @@ export function remove(block: Block, parent: ParentNode) { } } -export function setText(el: Element, oldVal: any, newVal: any) { +export function setText(el: Node, oldVal: any, newVal: any) { if ((newVal = toDisplayString(newVal)) !== oldVal) { el.textContent = newVal } @@ -104,7 +106,7 @@ export function setDynamicProp(el: Element, key: string, val: any) { } type Children = Record -export function children(n: ChildNode): Children { +export function children(n: Node): Children { return { ...Array.from(n.childNodes).map((n) => [n, children(n)]) } } diff --git a/packages/runtime-vapor/src/index.ts b/packages/runtime-vapor/src/index.ts index 0c56476ad8..3a88a738c9 100644 --- a/packages/runtime-vapor/src/index.ts +++ b/packages/runtime-vapor/src/index.ts @@ -44,3 +44,4 @@ export * from './scheduler' export * from './directive' export * from './dom' export * from './directives/vShow' +export { getCurrentInstance, type ComponentInternalInstance } from './component' diff --git a/packages/runtime-vapor/src/render.ts b/packages/runtime-vapor/src/render.ts index f55acd5760..e39ace1d07 100644 --- a/packages/runtime-vapor/src/render.ts +++ b/packages/runtime-vapor/src/render.ts @@ -54,12 +54,15 @@ export function mountComponent( new Proxy({ _: instance }, PublicInstanceProxyHandlers), ) const state = setupFn && setupFn(props, ctx) + let block: Block | null = null if (state && '__isScriptSetup' in state) { instance.setupState = proxyRefs(state) - return (instance.block = component.render(instance.proxy)) + block = component.render(instance.proxy) } else { - return (instance.block = state as Block) + block = state as Block } + if (block instanceof DocumentFragment) block = Array.from(block.childNodes) + return (instance.block = block) })! invokeDirectiveHook(instance, 'beforeMount') insert(block, instance.container) diff --git a/packages/runtime-vapor/src/template.ts b/packages/runtime-vapor/src/template.ts index aa3858b24d..5f12b80e65 100644 --- a/packages/runtime-vapor/src/template.ts +++ b/packages/runtime-vapor/src/template.ts @@ -1,4 +1,4 @@ -export const template = (str: string): (() => Node) => { +export const template = (str: string): (() => DocumentFragment) => { let cached = false let node: DocumentFragment return () => { @@ -14,7 +14,7 @@ export const template = (str: string): (() => Node) => { // repeated renders: clone from cache. This is more performant and // efficient when dealing with big lists where the template is repeated // many times. - return node.cloneNode(true) + return node.cloneNode(true) as DocumentFragment } } } diff --git a/playground/src/no-script.js b/playground/src/no-script.js new file mode 100644 index 0000000000..6394e5264b --- /dev/null +++ b/playground/src/no-script.js @@ -0,0 +1,5 @@ +import { template } from '@vue/runtime-vapor' + +export default () => { + return template('
')() +}