fix: make sure v-if and v-for work together

This commit is contained in:
Evan You 2019-09-22 20:55:18 -04:00
parent 3415bbd823
commit 0af0febfc2
2 changed files with 26 additions and 24 deletions

View File

@ -54,7 +54,7 @@ export interface TransformContext extends Required<TransformOptions> {
export function transform(root: RootNode, options: TransformOptions) {
const context = createTransformContext(root, options)
traverseChildren(root, context, context.ancestors)
traverseChildren(root, context)
}
function createTransformContext(
@ -103,12 +103,11 @@ function createTransformContext(
return context
}
function traverseChildren(
export function traverseChildren(
parent: ParentNode,
context: TransformContext,
ancestors: ParentNode[]
context: TransformContext
) {
ancestors = ancestors.concat(parent)
const ancestors = context.ancestors.concat(parent)
let i = 0
const nodeRemoved = () => {
i--
@ -118,39 +117,35 @@ function traverseChildren(
context.ancestors = ancestors
context.childIndex = i
context.onNodeRemoved = nodeRemoved
traverseNode((context.currentNode = parent.children[i]), context, ancestors)
traverseNode((context.currentNode = parent.children[i]), context)
}
}
function traverseNode(
node: ChildNode,
context: TransformContext,
ancestors: ParentNode[]
) {
export function traverseNode(node: ChildNode, context: TransformContext) {
// apply transform plugins
const { nodeTransforms } = context
for (let i = 0; i < nodeTransforms.length; i++) {
const plugin = nodeTransforms[i]
plugin(node, context)
// node may have been replaced
node = context.currentNode || node
}
if (!context.currentNode) {
// node was removed
return
if (!context.currentNode) {
// node was removed
return
} else {
// node may have been replaced
node = context.currentNode
}
}
// further traverse downwards
switch (node.type) {
case NodeTypes.IF:
for (let i = 0; i < node.branches.length; i++) {
traverseChildren(node.branches[i], context, ancestors)
traverseChildren(node.branches[i], context)
}
break
case NodeTypes.FOR:
case NodeTypes.ELEMENT:
traverseChildren(node, context, ancestors)
traverseChildren(node, context)
break
}
}
@ -169,11 +164,12 @@ export function createStructuralDirectiveTransform(
for (let i = 0; i < props.length; i++) {
const prop = props[i]
if (prop.type === NodeTypes.DIRECTIVE && matches(prop.name)) {
fn(node, prop, context)
// structural directives are removed after being processed
// to avoid infinite recursion
// structural directives are removed to avoid infinite recursion
// also we remove them *before* applying so that it can further
// traverse itself in case it moves the node around
props.splice(i, 1)
i--
fn(node, prop, context)
}
}
}

View File

@ -1,4 +1,7 @@
import { createStructuralDirectiveTransform } from '../transform'
import {
createStructuralDirectiveTransform,
traverseChildren
} from '../transform'
import {
NodeTypes,
ElementTypes,
@ -37,6 +40,9 @@ export const transformIf = createStructuralDirectiveTransform(
branch.children = [...comments, ...branch.children]
}
sibling.branches.push(branch)
// since the branch was removed, it will not be traversed.
// make sure to traverse here.
traverseChildren(branch, context)
} else {
context.onError(
createCompilerError(