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

View File

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