]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
fix(runtime-dom): support mounting app to svg container (#2929)
authorHcySunYang <HcySunYang@outlook.com>
Mon, 1 Mar 2021 16:51:32 +0000 (00:51 +0800)
committerGitHub <noreply@github.com>
Mon, 1 Mar 2021 16:51:32 +0000 (11:51 -0500)
fix #2926

packages/runtime-core/__tests__/hydration.spec.ts
packages/runtime-core/src/apiCreateApp.ts
packages/runtime-core/src/renderer.ts
packages/runtime-dom/__tests__/createApp.spec.ts [new file with mode: 0644]
packages/runtime-dom/src/index.ts

index 60978622bc6a564de481f67fd0218b35b7036a1d..4c7aa911bcc8fa517991ca1a225a6283b4180a38 100644 (file)
@@ -617,6 +617,20 @@ describe('SSR hydration', () => {
     expect(spy).toHaveBeenCalled()
   })
 
+  test('SVG as a mount container', () => {
+    const svgContainer = document.createElement('svg')
+    svgContainer.innerHTML = '<g></g>'
+    const app = createSSRApp({
+      render: () => h('g')
+    })
+
+    expect(
+      (app.mount(svgContainer).$.subTree as VNode<Node, Element> & {
+        el: Element
+      }).el instanceof SVGElement
+    )
+  })
+
   describe('mismatch handling', () => {
     test('text node', () => {
       const { container } = mountWithHydration(`foo`, () => 'bar')
index 869e5809f05e3393fde0f0184892d2ff347d1158..92cce58435b08081196dd06612de7ec2a53b766d 100644 (file)
@@ -27,7 +27,8 @@ export interface App<HostElement = any> {
   directive(name: string, directive: Directive): this
   mount(
     rootContainer: HostElement | string,
-    isHydrate?: boolean
+    isHydrate?: boolean,
+    isSVG?: boolean
   ): ComponentPublicInstance
   unmount(): void
   provide<T>(key: InjectionKey<T> | string, value: T): this
@@ -224,7 +225,11 @@ export function createAppAPI<HostElement>(
         return app
       },
 
-      mount(rootContainer: HostElement, isHydrate?: boolean): any {
+      mount(
+        rootContainer: HostElement,
+        isHydrate?: boolean,
+        isSVG?: boolean
+      ): any {
         if (!isMounted) {
           const vnode = createVNode(
             rootComponent as ConcreteComponent,
@@ -237,14 +242,14 @@ export function createAppAPI<HostElement>(
           // HMR root reload
           if (__DEV__) {
             context.reload = () => {
-              render(cloneVNode(vnode), rootContainer)
+              render(cloneVNode(vnode), rootContainer, isSVG)
             }
           }
 
           if (isHydrate && hydrate) {
             hydrate(vnode as VNode<Node, Element>, rootContainer as any)
           } else {
-            render(vnode, rootContainer)
+            render(vnode, rootContainer, isSVG)
           }
           isMounted = true
           app._container = rootContainer
index bc1d154527bce0201d417429b9f44c3b33aa6220..b7973284f705362a067b13e88ce5a3d874feedeb 100644 (file)
@@ -93,7 +93,8 @@ export interface HydrationRenderer extends Renderer<Element> {
 
 export type RootRenderFunction<HostElement = RendererElement> = (
   vnode: VNode | null,
-  container: HostElement
+  container: HostElement,
+  isSVG?: boolean
 ) => void
 
 export interface RendererOptions<
@@ -2202,13 +2203,13 @@ function baseCreateRenderer(
     return hostNextSibling((vnode.anchor || vnode.el)!)
   }
 
-  const render: RootRenderFunction = (vnode, container) => {
+  const render: RootRenderFunction = (vnode, container, isSVG) => {
     if (vnode == null) {
       if (container._vnode) {
         unmount(container._vnode, null, null, true)
       }
     } else {
-      patch(container._vnode || null, vnode, container)
+      patch(container._vnode || null, vnode, container, null, null, null, isSVG)
     }
     flushPostFlushCbs()
     container._vnode = vnode
diff --git a/packages/runtime-dom/__tests__/createApp.spec.ts b/packages/runtime-dom/__tests__/createApp.spec.ts
new file mode 100644 (file)
index 0000000..00c9282
--- /dev/null
@@ -0,0 +1,15 @@
+import { createApp, h } from '../src'
+
+describe('createApp for dom', () => {
+  // #2926
+  test('mount to SVG container', () => {
+    const root = document.createElementNS('http://www.w3.org/2000/svg', 'svg')
+    createApp({
+      render() {
+        return h('g')
+      }
+    }).mount(root)
+    expect(root.children.length).toBe(1)
+    expect(root.children[0] instanceof SVGElement).toBe(true)
+  })
+})
index 8a66ec994c9094fdbd8a73aa614afa7cc0604b47..773470621fe5fd621158138377d9cfc0a2cb962c 100644 (file)
@@ -69,7 +69,7 @@ export const createApp = ((...args) => {
     }
     // clear content before mounting
     container.innerHTML = ''
-    const proxy = mount(container)
+    const proxy = mount(container, false, container instanceof SVGElement)
     if (container instanceof Element) {
       container.removeAttribute('v-cloak')
       container.setAttribute('data-v-app', '')
@@ -92,7 +92,7 @@ export const createSSRApp = ((...args) => {
   app.mount = (containerOrSelector: Element | ShadowRoot | string): any => {
     const container = normalizeContainer(containerOrSelector)
     if (container) {
-      return mount(container, true)
+      return mount(container, true, container instanceof SVGElement)
     }
   }