fix(teleport): Teleport into SVG elements (#2648)

fix #2652
This commit is contained in:
Yasser Lahbibi 2020-11-30 23:30:41 +01:00 committed by GitHub
parent 7a1a782642
commit cd92836223
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 41 additions and 3 deletions

View File

@ -7,10 +7,11 @@ import {
Text,
ref,
nextTick,
markRaw
markRaw,
defineComponent
} from '@vue/runtime-test'
import { createVNode, Fragment } from '../../src/vnode'
import { compile } from 'vue'
import { compile, render as domRender } from 'vue'
describe('renderer: teleport', () => {
test('should work', () => {
@ -33,6 +34,37 @@ describe('renderer: teleport', () => {
)
})
test('should work with SVG', async () => {
const root = document.createElement('div')
const svg = ref()
const circle = ref()
const Comp = defineComponent({
setup() {
return {
svg,
circle
}
},
template: `
<svg ref="svg"></svg>
<teleport :to="svg" v-if="svg">
<circle ref="circle"></circle>
</teleport>`
})
domRender(h(Comp), root)
await nextTick()
expect(root.innerHTML).toMatchInlineSnapshot(
`"<svg><circle></circle></svg><!--teleport start--><!--teleport end-->"`
)
expect(svg.value.namespaceURI).toBe('http://www.w3.org/2000/svg')
expect(circle.value.namespaceURI).toBe('http://www.w3.org/2000/svg')
})
test('should update target', async () => {
const targetA = nodeOps.createElement('div')
const targetB = nodeOps.createElement('div')

View File

@ -24,6 +24,9 @@ export const isTeleport = (type: any): boolean => type.__isTeleport
export const isTeleportDisabled = (props: VNode['props']): boolean =>
props && (props.disabled || props.disabled === '')
const isTargetSVG = (target: RendererElement): boolean =>
typeof SVGElement !== 'undefined' && target instanceof SVGElement
const resolveTarget = <T = RendererElement>(
props: TeleportProps | null,
select: RendererOptions['querySelector']
@ -80,6 +83,7 @@ export const TeleportImpl = {
const disabled = isTeleportDisabled(n2.props)
const { shapeFlag, children } = n2
if (n1 == null) {
// insert anchors in the main view
const placeholder = (n2.el = __DEV__
@ -90,11 +94,12 @@ export const TeleportImpl = {
: createText(''))
insert(placeholder, container, anchor)
insert(mainAnchor, container, anchor)
const target = (n2.target = resolveTarget(n2.props, querySelector))
const targetAnchor = (n2.targetAnchor = createText(''))
if (target) {
insert(targetAnchor, target)
// #2652 we could be teleporting from a non-SVG tree into an SVG tree
isSVG = isSVG || isTargetSVG(target)
} else if (__DEV__ && !disabled) {
warn('Invalid Teleport target on mount:', target, `(${typeof target})`)
}
@ -129,6 +134,7 @@ export const TeleportImpl = {
const wasDisabled = isTeleportDisabled(n1.props)
const currentContainer = wasDisabled ? container : target
const currentAnchor = wasDisabled ? mainAnchor : targetAnchor
isSVG = isSVG || isTargetSVG(target)
if (n2.dynamicChildren) {
// fast path when the teleport happens to be a block root