]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
fix(compiler): generate function ref for script setup if inline is ture. (#4492)
authorygj6 <7699524+ygj6@users.noreply.github.com>
Thu, 2 Sep 2021 15:27:20 +0000 (23:27 +0800)
committerGitHub <noreply@github.com>
Thu, 2 Sep 2021 15:27:20 +0000 (11:27 -0400)
packages/compiler-core/__tests__/transforms/transformElement.spec.ts
packages/compiler-core/src/transforms/transformElement.ts

index d2780f35fa7fa5ad2ad07641580aa7d2511276cb..16a4c0443223e47debd5ebf193496f67a3b0bed6 100644 (file)
@@ -936,6 +936,74 @@ describe('compiler: element transform', () => {
       expect(node.patchFlag).toBe(genFlagText(PatchFlags.NEED_PATCH))
     })
 
+    test('the binding exists (inline ref input)', () => {
+      const { node } = parseWithElementTransform(`<input ref="input"/>`, {
+        inline: true,
+        bindingMetadata: {
+          input: BindingTypes.SETUP_REF
+        }
+      })
+      expect(node.props).toMatchObject({
+        type: NodeTypes.JS_OBJECT_EXPRESSION,
+        properties: [
+          {
+            type: NodeTypes.JS_PROPERTY,
+            key: {
+              type: NodeTypes.SIMPLE_EXPRESSION,
+              content: 'ref',
+              isStatic: true
+            },
+            value: {
+              type: NodeTypes.JS_FUNCTION_EXPRESSION,
+              params: ['_value', '_refs'],
+              body: {
+                type: NodeTypes.JS_BLOCK_STATEMENT,
+                body: [
+                  {
+                    content: `_refs['input'] = _value`
+                  },
+                  {
+                    content: 'input.value = _value'
+                  }
+                ]
+              }
+            }
+          }
+        ]
+      })
+    })
+
+    test('the binding not exists (inline ref input)', () => {
+      const { node } = parseWithElementTransform(`<input ref="input"/>`, {
+        inline: true
+      })
+      expect(node.props).toMatchObject({
+        type: NodeTypes.JS_OBJECT_EXPRESSION,
+        properties: [
+          {
+            type: NodeTypes.JS_PROPERTY,
+            key: {
+              type: NodeTypes.SIMPLE_EXPRESSION,
+              content: 'ref',
+              isStatic: true
+            },
+            value: {
+              type: NodeTypes.JS_FUNCTION_EXPRESSION,
+              params: ['_value', '_refs'],
+              body: {
+                type: NodeTypes.JS_BLOCK_STATEMENT,
+                body: [
+                  {
+                    content: `_refs['input'] = _value`
+                  }
+                ]
+              }
+            }
+          }
+        ]
+      })
+    })
+
     test('HYDRATE_EVENTS', () => {
       // ignore click events (has dedicated fast path)
       const { node } = parseWithElementTransform(`<div @click="foo" />`, {
index e31a2ccbf0a7cdfb7684b4732965c32991ae6d08..c471d2a4b84a569ac90e7dcebc78ec3a325ad4f3 100644 (file)
@@ -19,7 +19,10 @@ import {
   TemplateTextChildNode,
   DirectiveArguments,
   createVNodeCall,
-  ConstantTypes
+  ConstantTypes,
+  JSChildNode,
+  createFunctionExpression,
+  createBlockStatement
 } from '../ast'
 import {
   PatchFlags,
@@ -58,7 +61,7 @@ import {
 } from '../utils'
 import { buildSlots } from './vSlot'
 import { getConstantType } from './hoistStatic'
-import { BindingTypes } from '../options'
+import { BindingMetadata, BindingTypes } from '../options'
 import {
   checkCompatEnabled,
   CompilerDeprecationTypes,
@@ -459,19 +462,21 @@ export function buildProps(
     const prop = props[i]
     if (prop.type === NodeTypes.ATTRIBUTE) {
       const { loc, name, value } = prop
-      let isStatic = true
+      let valueNode = createSimpleExpression(
+        value ? value.content : '',
+        true,
+        value ? value.loc : loc
+      ) as JSChildNode
       if (name === 'ref') {
         hasRef = true
         // in inline mode there is no setupState object, so we can't use string
         // keys to set the ref. Instead, we need to transform it to pass the
         // acrtual ref instead.
-        if (
-          !__BROWSER__ &&
-          value &&
-          context.inline &&
-          context.bindingMetadata[value.content]
-        ) {
-          isStatic = false
+        if (!__BROWSER__ && context.inline && value?.content) {
+          valueNode = createFunctionExpression(['_value', '_refs'])
+          valueNode.body = createBlockStatement(
+            processInlineRef(context.bindingMetadata, value.content)
+          )
         }
       }
       // skip is on <component>, or is="vue:xxx"
@@ -494,11 +499,7 @@ export function buildProps(
             true,
             getInnerRange(loc, 0, name.length)
           ),
-          createSimpleExpression(
-            value ? value.content : '',
-            isStatic,
-            value ? value.loc : loc
-          )
+          valueNode
         )
       )
     } else {
@@ -891,3 +892,17 @@ function stringifyDynamicPropNames(props: string[]): string {
 function isComponentTag(tag: string) {
   return tag[0].toLowerCase() + tag.slice(1) === 'component'
 }
+
+function processInlineRef(
+  bindings: BindingMetadata,
+  raw: string
+): JSChildNode[] {
+  const body = [createSimpleExpression(`_refs['${raw}'] = _value`)]
+  const type = bindings[raw]
+  if (type === BindingTypes.SETUP_REF) {
+    body.push(createSimpleExpression(`${raw}.value = _value`))
+  } else if (type === BindingTypes.SETUP_LET) {
+    body.push(createSimpleExpression(`${raw} = _value`))
+  }
+  return body
+}