]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
fix(compiler-core): make v-once work with v-if/else-if/else (#2182)
authorHcySunYang <HcySunYang@outlook.com>
Mon, 5 Oct 2020 15:58:37 +0000 (23:58 +0800)
committerGitHub <noreply@github.com>
Mon, 5 Oct 2020 15:58:37 +0000 (11:58 -0400)
Partial fix for #2035

packages/compiler-core/__tests__/transforms/vOnce.spec.ts
packages/compiler-core/src/ast.ts
packages/compiler-core/src/transforms/vIf.ts

index 3983aa9605a008434703d39dcc5756a15b23dba8..a18a0947d00916e1acaa89bb9e749067673af504 100644 (file)
@@ -99,15 +99,26 @@ describe('compiler: v-once transform', () => {
     expect(generate(root).code).toMatchSnapshot()
   })
 
-  test('with v-if', () => {
-    const root = transformWithOnce(`<div v-if="true" v-once />`)
+  test('with v-if/else', () => {
+    const root = transformWithOnce(`<div v-if="BOOLEAN" v-once /><p v-else/>`)
     expect(root.cached).toBe(1)
     expect(root.helpers).toContain(SET_BLOCK_TRACKING)
     expect(root.children[0]).toMatchObject({
       type: NodeTypes.IF,
-      // should cache the entire v-if expression, not just a single branch
+      // should cache the entire v-if/else-if/else expression, not just a single branch
       codegenNode: {
-        type: NodeTypes.JS_CACHE_EXPRESSION
+        type: NodeTypes.JS_CACHE_EXPRESSION,
+        value: {
+          type: NodeTypes.JS_CONDITIONAL_EXPRESSION,
+          consequent: {
+            type: NodeTypes.VNODE_CALL,
+            tag: `"div"`
+          },
+          alternate: {
+            type: NodeTypes.VNODE_CALL,
+            tag: `"p"`
+          }
+        }
       }
     })
   })
index 42c93402616330c35a09b9671b1692608927bdde..35849833c66bbb40a87aaf030a33f4dd69c82897 100644 (file)
@@ -236,7 +236,7 @@ export interface CompoundExpressionNode extends Node {
 export interface IfNode extends Node {
   type: NodeTypes.IF
   branches: IfBranchNode[]
-  codegenNode?: IfConditionalExpression
+  codegenNode?: IfConditionalExpression | CacheExpression // <div v-if v-once>
 }
 
 export interface IfBranchNode extends Node {
index 2c00349254d3adef61dd63cd0b1f185c4966e92e..00832a9acecf686594a3adfe2a90bf14119c692f 100644 (file)
@@ -20,7 +20,8 @@ import {
   IfNode,
   createVNodeCall,
   AttributeNode,
-  locStub
+  locStub,
+  CacheExpression
 } from '../ast'
 import { createCompilerError, ErrorCodes } from '../errors'
 import { processExpression } from './transformExpression'
@@ -62,13 +63,7 @@ export const transformIf = createStructuralDirectiveTransform(
           ) as IfConditionalExpression
         } else {
           // attach this branch's codegen node to the v-if root.
-          let parentCondition = ifNode.codegenNode!
-          while (
-            parentCondition.alternate.type ===
-            NodeTypes.JS_CONDITIONAL_EXPRESSION
-          ) {
-            parentCondition = parentCondition.alternate
-          }
+          const parentCondition = getParentCondition(ifNode.codegenNode!)
           parentCondition.alternate = createCodegenNodeForBranch(
             branch,
             key + ifNode.branches.length - 1,
@@ -293,3 +288,19 @@ function isSameKey(
   }
   return true
 }
+
+function getParentCondition(
+  node: IfConditionalExpression | CacheExpression
+): IfConditionalExpression {
+  while (true) {
+    if (node.type === NodeTypes.JS_CONDITIONAL_EXPRESSION) {
+      if (node.alternate.type === NodeTypes.JS_CONDITIONAL_EXPRESSION) {
+        node = node.alternate
+      } else {
+        return node
+      }
+    } else if (node.type === NodeTypes.JS_CACHE_EXPRESSION) {
+      node = node.value as IfConditionalExpression
+    }
+  }
+}