feat: support ref in v-for, remove compat deprecation warnings

This commit is contained in:
Evan You
2021-12-10 23:49:01 +08:00
parent a1167c57e5
commit 41c18effea
11 changed files with 224 additions and 334 deletions

View File

@@ -20,7 +20,6 @@ export const enum CompilerDeprecationTypes {
COMPILER_V_BIND_OBJECT_ORDER = 'COMPILER_V_BIND_OBJECT_ORDER',
COMPILER_V_ON_NATIVE = 'COMPILER_V_ON_NATIVE',
COMPILER_V_IF_V_FOR_PRECEDENCE = 'COMPILER_V_IF_V_FOR_PRECEDENCE',
COMPILER_V_FOR_REF = 'COMPILER_V_FOR_REF',
COMPILER_NATIVE_TEMPLATE = 'COMPILER_NATIVE_TEMPLATE',
COMPILER_INLINE_TEMPLATE = 'COMPILER_INLINE_TEMPLATE',
COMPILER_FILTERS = 'COMPILER_FILTER'
@@ -79,13 +78,6 @@ const deprecationData: Record<CompilerDeprecationTypes, DeprecationData> = {
link: `https://v3.vuejs.org/guide/migration/v-if-v-for.html`
},
[CompilerDeprecationTypes.COMPILER_V_FOR_REF]: {
message:
`Ref usage on v-for no longer creates array ref values in Vue 3. ` +
`Consider using function refs or refactor to avoid ref usage altogether.`,
link: `https://v3.vuejs.org/guide/migration/array-refs.html`
},
[CompilerDeprecationTypes.COMPILER_NATIVE_TEMPLATE]: {
message:
`<template> with no special directives will render as a native template ` +

View File

@@ -19,10 +19,7 @@ import {
TemplateTextChildNode,
DirectiveArguments,
createVNodeCall,
ConstantTypes,
JSChildNode,
createFunctionExpression,
createBlockStatement
ConstantTypes
} from '../ast'
import {
PatchFlags,
@@ -48,8 +45,7 @@ import {
KEEP_ALIVE,
SUSPENSE,
UNREF,
GUARD_REACTIVE_PROPS,
IS_REF
GUARD_REACTIVE_PROPS
} from '../runtimeHelpers'
import {
getInnerRange,
@@ -467,20 +463,32 @@ export function buildProps(
const prop = props[i]
if (prop.type === NodeTypes.ATTRIBUTE) {
const { loc, name, value } = prop
let valueNode = createSimpleExpression(
value ? value.content : '',
true,
value ? value.loc : loc
) as JSChildNode
let isStatic = true
if (name === 'ref') {
hasRef = true
if (context.scopes.vFor > 0) {
properties.push(
createObjectProperty(
createSimpleExpression('ref_for', true),
createSimpleExpression('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
// actual ref instead.
if (!__BROWSER__ && context.inline && value?.content) {
valueNode = createFunctionExpression(['_value', '_refs'])
valueNode.body = createBlockStatement(
processInlineRef(context, value.content)
if (
!__BROWSER__ &&
value &&
context.inline &&
context.bindingMetadata[value.content]
) {
isStatic = false
properties.push(
createObjectProperty(
createSimpleExpression('ref_key', true),
createSimpleExpression(value.content, true, value.loc)
)
)
}
}
@@ -504,7 +512,11 @@ export function buildProps(
true,
getInnerRange(loc, 0, name.length)
),
valueNode
createSimpleExpression(
value ? value.content : '',
isStatic,
value ? value.loc : loc
)
)
)
} else {
@@ -555,6 +567,15 @@ export function buildProps(
shouldUseBlock = true
}
if (isVBind && isStaticArgOf(arg, 'ref') && context.scopes.vFor > 0) {
properties.push(
createObjectProperty(
createSimpleExpression('ref_for', true),
createSimpleExpression('true')
)
)
}
// special case for v-bind and v-on with no argument
if (!arg && (isVBind || isVOn)) {
hasDynamicKeys = true
@@ -654,25 +675,6 @@ export function buildProps(
}
}
}
if (
__COMPAT__ &&
prop.type === NodeTypes.ATTRIBUTE &&
prop.name === 'ref' &&
context.scopes.vFor > 0 &&
checkCompatEnabled(
CompilerDeprecationTypes.COMPILER_V_FOR_REF,
context,
prop.loc
)
) {
properties.push(
createObjectProperty(
createSimpleExpression('refInFor', true),
createSimpleExpression('true', false)
)
)
}
}
let propsExpression: PropsExpression | undefined = undefined
@@ -914,30 +916,3 @@ function stringifyDynamicPropNames(props: string[]): string {
function isComponentTag(tag: string) {
return tag === 'component' || tag === 'Component'
}
function processInlineRef(
context: TransformContext,
raw: string
): JSChildNode[] {
const body = [createSimpleExpression(`_refs['${raw}'] = _value`)]
const { bindingMetadata, helperString } = context
const type = bindingMetadata[raw]
if (type === BindingTypes.SETUP_REF) {
body.push(createSimpleExpression(`${raw}.value = _value`))
} else if (type === BindingTypes.SETUP_MAYBE_REF) {
body.push(
createSimpleExpression(
`${helperString(IS_REF)}(${raw}) && (${raw}.value = _value)`
)
)
} else if (type === BindingTypes.SETUP_LET) {
body.push(
createSimpleExpression(
`${helperString(
IS_REF
)}(${raw}) ? ${raw}.value = _value : ${raw} = _value`
)
)
}
return body
}