From 4cd282b0a17589ef9ca2649e7beb0bdee4a73c57 Mon Sep 17 00:00:00 2001 From: ygj6 <7699524+ygj6@users.noreply.github.com> Date: Thu, 2 Sep 2021 23:27:20 +0800 Subject: [PATCH] fix(compiler): generate function ref for script setup if inline is ture. (#4492) --- .../transforms/transformElement.spec.ts | 68 +++++++++++++++++++ .../src/transforms/transformElement.ts | 45 ++++++++---- 2 files changed, 98 insertions(+), 15 deletions(-) diff --git a/packages/compiler-core/__tests__/transforms/transformElement.spec.ts b/packages/compiler-core/__tests__/transforms/transformElement.spec.ts index d2780f35fa7..16a4c044322 100644 --- a/packages/compiler-core/__tests__/transforms/transformElement.spec.ts +++ b/packages/compiler-core/__tests__/transforms/transformElement.spec.ts @@ -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(``, { + 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(``, { + 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(`
`, { diff --git a/packages/compiler-core/src/transforms/transformElement.ts b/packages/compiler-core/src/transforms/transformElement.ts index e31a2ccbf0a..c471d2a4b84 100644 --- a/packages/compiler-core/src/transforms/transformElement.ts +++ b/packages/compiler-core/src/transforms/transformElement.ts @@ -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 , 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 +}