fix: inherit el for static nodes inside keyed template fragment (#2089)

fix #2080
This commit is contained in:
underfin 2020-09-15 04:02:29 +08:00 committed by GitHub
parent 612eb6712a
commit a32870a8f6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 60 additions and 6 deletions

View File

@ -10,9 +10,13 @@ import {
dumpOps, dumpOps,
NodeOpTypes, NodeOpTypes,
serializeInner, serializeInner,
createTextVNode createTextVNode,
createBlock,
openBlock,
createCommentVNode
} from '@vue/runtime-test' } from '@vue/runtime-test'
import { PatchFlags } from '@vue/shared' import { PatchFlags } from '@vue/shared'
import { renderList } from '../src/helpers/renderList'
describe('renderer: fragment', () => { describe('renderer: fragment', () => {
it('should allow returning multiple component root nodes', () => { it('should allow returning multiple component root nodes', () => {
@ -269,4 +273,46 @@ describe('renderer: fragment', () => {
render(null, root) render(null, root)
expect(serializeInner(root)).toBe(``) expect(serializeInner(root)).toBe(``)
}) })
// #2080
test('`template` keyed fragment w/ comment + hoisted node', () => {
const root = nodeOps.createElement('div')
const hoisted = h('span')
const renderFn = (items: string[]) => {
return (
openBlock(true),
createBlock(
Fragment,
null,
renderList(items, item => {
return (
openBlock(),
createBlock(
Fragment,
{ key: item },
[
createCommentVNode('comment'),
hoisted,
createVNode('div', null, item, PatchFlags.TEXT)
],
PatchFlags.STABLE_FRAGMENT
)
)
}),
PatchFlags.KEYED_FRAGMENT
)
)
}
render(renderFn(['one', 'two']), root)
expect(serializeInner(root)).toBe(
`<!--comment--><span></span><div>one</div><!--comment--><span></span><div>two</div>`
)
render(renderFn(['two', 'one']), root)
expect(serializeInner(root)).toBe(
`<!--comment--><span></span><div>two</div><!--comment--><span></span><div>one</div>`
)
})
}) })

View File

@ -1153,8 +1153,10 @@ function baseCreateRenderer(
parentSuspense, parentSuspense,
isSVG isSVG
) )
if (__DEV__ && parentComponent && parentComponent.type.__hmrId) { // #2080 if the stable fragment has a key, it's a <template v-for> that may
traverseStaticChildren(n1, n2) // get moved around. Make sure all root level vnodes inherit el.
if (n2.key != null) {
traverseStaticChildren(n1, n2, true /* shallow */)
} }
} else { } else {
// keyed / unkeyed, or manual fragments. // keyed / unkeyed, or manual fragments.
@ -2166,9 +2168,12 @@ function baseCreateRenderer(
* inside a block also inherit the DOM element from the previous tree so that * inside a block also inherit the DOM element from the previous tree so that
* HMR updates (which are full updates) can retrieve the element for patching. * HMR updates (which are full updates) can retrieve the element for patching.
* *
* Dev only. * #2080
* Inside keyed `template` fragment static children, if a fragment is moved,
* the children will always moved so that need inherit el form previous nodes
* to ensure correct moved position.
*/ */
const traverseStaticChildren = (n1: VNode, n2: VNode) => { const traverseStaticChildren = (n1: VNode, n2: VNode, shallow = false) => {
const ch1 = n1.children const ch1 = n1.children
const ch2 = n2.children const ch2 = n2.children
if (isArray(ch1) && isArray(ch2)) { if (isArray(ch1) && isArray(ch2)) {
@ -2181,7 +2186,10 @@ function baseCreateRenderer(
if (c2.patchFlag <= 0 || c2.patchFlag === PatchFlags.HYDRATE_EVENTS) { if (c2.patchFlag <= 0 || c2.patchFlag === PatchFlags.HYDRATE_EVENTS) {
c2.el = c1.el c2.el = c1.el
} }
traverseStaticChildren(c1, c2) if (!shallow) traverseStaticChildren(c1, c2)
}
if (__DEV__ && c2.type === Comment) {
c2.el = c1.el
} }
} }
} }