Skip to content

Commit cd92836

Browse files
authoredNov 30, 2020
fix(teleport): Teleport into SVG elements (#2648)
fix #2652
1 parent 7a1a782 commit cd92836

File tree

2 files changed

+41
-3
lines changed

2 files changed

+41
-3
lines changed
 

‎packages/runtime-core/__tests__/components/Teleport.spec.ts

+34-2
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,11 @@ import {
77
Text,
88
ref,
99
nextTick,
10-
markRaw
10+
markRaw,
11+
defineComponent
1112
} from '@vue/runtime-test'
1213
import { createVNode, Fragment } from '../../src/vnode'
13-
import { compile } from 'vue'
14+
import { compile, render as domRender } from 'vue'
1415

1516
describe('renderer: teleport', () => {
1617
test('should work', () => {
@@ -33,6 +34,37 @@ describe('renderer: teleport', () => {
3334
)
3435
})
3536

37+
test('should work with SVG', async () => {
38+
const root = document.createElement('div')
39+
const svg = ref()
40+
const circle = ref()
41+
42+
const Comp = defineComponent({
43+
setup() {
44+
return {
45+
svg,
46+
circle
47+
}
48+
},
49+
template: `
50+
<svg ref="svg"></svg>
51+
<teleport :to="svg" v-if="svg">
52+
<circle ref="circle"></circle>
53+
</teleport>`
54+
})
55+
56+
domRender(h(Comp), root)
57+
58+
await nextTick()
59+
60+
expect(root.innerHTML).toMatchInlineSnapshot(
61+
`"<svg><circle></circle></svg><!--teleport start--><!--teleport end-->"`
62+
)
63+
64+
expect(svg.value.namespaceURI).toBe('http://www.w3.org/2000/svg')
65+
expect(circle.value.namespaceURI).toBe('http://www.w3.org/2000/svg')
66+
})
67+
3668
test('should update target', async () => {
3769
const targetA = nodeOps.createElement('div')
3870
const targetB = nodeOps.createElement('div')

‎packages/runtime-core/src/components/Teleport.ts

+7-1
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@ export const isTeleport = (type: any): boolean => type.__isTeleport
2424
export const isTeleportDisabled = (props: VNode['props']): boolean =>
2525
props && (props.disabled || props.disabled === '')
2626

27+
const isTargetSVG = (target: RendererElement): boolean =>
28+
typeof SVGElement !== 'undefined' && target instanceof SVGElement
29+
2730
const resolveTarget = <T = RendererElement>(
2831
props: TeleportProps | null,
2932
select: RendererOptions['querySelector']
@@ -80,6 +83,7 @@ export const TeleportImpl = {
8083

8184
const disabled = isTeleportDisabled(n2.props)
8285
const { shapeFlag, children } = n2
86+
8387
if (n1 == null) {
8488
// insert anchors in the main view
8589
const placeholder = (n2.el = __DEV__
@@ -90,11 +94,12 @@ export const TeleportImpl = {
9094
: createText(''))
9195
insert(placeholder, container, anchor)
9296
insert(mainAnchor, container, anchor)
93-
9497
const target = (n2.target = resolveTarget(n2.props, querySelector))
9598
const targetAnchor = (n2.targetAnchor = createText(''))
9699
if (target) {
97100
insert(targetAnchor, target)
101+
// #2652 we could be teleporting from a non-SVG tree into an SVG tree
102+
isSVG = isSVG || isTargetSVG(target)
98103
} else if (__DEV__ && !disabled) {
99104
warn('Invalid Teleport target on mount:', target, `(${typeof target})`)
100105
}
@@ -129,6 +134,7 @@ export const TeleportImpl = {
129134
const wasDisabled = isTeleportDisabled(n1.props)
130135
const currentContainer = wasDisabled ? container : target
131136
const currentAnchor = wasDisabled ? mainAnchor : targetAnchor
137+
isSVG = isSVG || isTargetSVG(target)
132138

133139
if (n2.dynamicChildren) {
134140
// fast path when the teleport happens to be a block root

0 commit comments

Comments
 (0)
Please sign in to comment.