feat(compiler-core/v-model): avoid patching v-model handler when possible

This commit is contained in:
Evan You
2019-10-16 13:56:00 -04:00
parent 48b79d02e8
commit 5481f76ce8
4 changed files with 102 additions and 21 deletions

View File

@@ -193,21 +193,21 @@ export function buildProps(
const analyzePatchFlag = ({ key, value }: Property) => {
if (key.type === NodeTypes.SIMPLE_EXPRESSION && key.isStatic) {
if (
value.type !== NodeTypes.SIMPLE_EXPRESSION ||
// E.g: <p :foo="1 + 2" />.
// Do not add prop `foo` to `dynamicPropNames`.
(!value.isStatic && !value.isConstant)
(value.type === NodeTypes.SIMPLE_EXPRESSION ||
value.type === NodeTypes.COMPOUND_EXPRESSION) &&
isStaticNode(value)
) {
const name = key.content
if (name === 'ref') {
hasRef = true
} else if (name === 'class') {
hasClassBinding = true
} else if (name === 'style') {
hasStyleBinding = true
} else if (name !== 'key') {
dynamicPropNames.push(name)
}
return
}
const name = key.content
if (name === 'ref') {
hasRef = true
} else if (name === 'class') {
hasClassBinding = true
} else if (name === 'style') {
hasStyleBinding = true
} else if (name !== 'key') {
dynamicPropNames.push(name)
}
} else {
hasDynamicKeys = true

View File

@@ -1,13 +1,16 @@
import { DirectiveTransform } from '../transform'
import { DirectiveTransform, TransformContext } from '../transform'
import {
createSimpleExpression,
createObjectProperty,
createCompoundExpression,
NodeTypes,
Property
Property,
CompoundExpressionNode,
createInterpolation
} from '../ast'
import { createCompilerError, ErrorCodes } from '../errors'
import { isMemberExpression } from '../utils'
import { isObject } from '@vue/shared'
export const transformModel: DirectiveTransform = (dir, node, context) => {
const { exp, arg } = dir
@@ -38,13 +41,23 @@ export const transformModel: DirectiveTransform = (dir, node, context) => {
])
: createSimpleExpression('onUpdate:modelValue', true)
let assignmentChildren =
exp.type === NodeTypes.SIMPLE_EXPRESSION ? [exp] : exp.children
// For a member expression used in assignment, it only needs to be updated
// if the expression involves scope variables. Otherwise we can mark the
// expression as constant to avoid it being included in `dynamicPropNames`
// of the element. This optimization relies on `prefixIdentifiers: true`.
if (!__BROWSER__ && context.prefixIdentifiers) {
assignmentChildren = assignmentChildren.map(c => toConstant(c, context))
}
const props = [
createObjectProperty(propName, dir.exp!),
createObjectProperty(
eventName,
createCompoundExpression([
`$event => (`,
...(exp.type === NodeTypes.SIMPLE_EXPRESSION ? [exp] : exp.children),
...assignmentChildren,
` = $event)`
])
)
@@ -57,6 +70,30 @@ export const transformModel: DirectiveTransform = (dir, node, context) => {
return createTransformProps(props)
}
function toConstant(
exp: CompoundExpressionNode | CompoundExpressionNode['children'][0],
context: TransformContext
): any {
if (!isObject(exp) || exp.type === NodeTypes.TEXT) {
return exp
}
if (exp.type === NodeTypes.SIMPLE_EXPRESSION) {
if (exp.isStatic || context.identifiers[exp.content]) {
return exp
}
return {
...exp,
isConstant: true
}
} else if (exp.type === NodeTypes.COMPOUND_EXPRESSION) {
return createCompoundExpression(
exp.children.map(c => toConstant(c, context))
)
} else if (exp.type === NodeTypes.INTERPOLATION) {
return createInterpolation(toConstant(exp.content, context), exp.loc)
}
}
function createTransformProps(props: Property[] = []) {
return { props, needRuntime: false }
}