wip(compiler-dom): v-model runtime

This commit is contained in:
Evan You
2019-10-10 18:02:51 -04:00
parent 145559e170
commit d376439167
21 changed files with 245 additions and 95 deletions

View File

@@ -15,7 +15,7 @@ import {
createObjectExpression,
Property
} from '../ast'
import { isArray, PatchFlags, PatchFlagNames } from '@vue/shared'
import { PatchFlags, PatchFlagNames, isSymbol } from '@vue/shared'
import { createCompilerError, ErrorCodes } from '../errors'
import {
CREATE_VNODE,
@@ -28,6 +28,10 @@ import {
import { getInnerRange, isVSlot, toValidAssetId } from '../utils'
import { buildSlots } from './vSlot'
// some directive transforms (e.g. v-model) may return a symbol for runtime
// import, which should be used instead of a resolveDirective call.
const directiveImportMap = new WeakMap<DirectiveNode, symbol>()
// generate a JavaScript AST for this element's codegen
export const transformElement: NodeTransform = (node, context) => {
if (node.type === NodeTypes.ELEMENT) {
@@ -137,9 +141,7 @@ export const transformElement: NodeTransform = (node, context) => {
[
vnode,
createArrayExpression(
runtimeDirectives.map(dir => {
return createDirectiveArgs(dir, context)
}),
runtimeDirectives.map(dir => createDirectiveArgs(dir, context)),
loc
)
],
@@ -274,15 +276,13 @@ export function buildProps(
if (directiveTransform) {
// has built-in directive transform.
const { props, needRuntime } = directiveTransform(prop, node, context)
if (isArray(props)) {
properties.push(...props)
properties.forEach(analyzePatchFlag)
} else {
properties.push(props)
analyzePatchFlag(props)
}
props.forEach(analyzePatchFlag)
properties.push(...props)
if (needRuntime) {
runtimeDirectives.push(prop)
if (isSymbol(needRuntime)) {
directiveImportMap.set(prop, needRuntime)
}
}
} else {
// no built-in transform, this is a user custom directive.
@@ -362,7 +362,12 @@ function dedupeProperties(properties: Property[]): Property[] {
const name = prop.key.content
const existing = knownProps[name]
if (existing) {
if (name.startsWith('on') || name === 'style' || name === 'class') {
if (
name === 'style' ||
name === 'class' ||
name.startsWith('on') ||
name.startsWith('vnode')
) {
mergeAsArray(existing, prop)
}
// unexpected duplicate, should have emitted error during parse
@@ -389,12 +394,17 @@ function createDirectiveArgs(
dir: DirectiveNode,
context: TransformContext
): ArrayExpression {
// inject statement for resolving directive
context.helper(RESOLVE_DIRECTIVE)
context.directives.add(dir.name)
const dirArgs: ArrayExpression['elements'] = [
toValidAssetId(dir.name, `directive`)
]
const dirArgs: ArrayExpression['elements'] = []
const runtime = directiveImportMap.get(dir)
if (runtime) {
context.helper(runtime)
dirArgs.push(context.helperString(runtime))
} else {
// inject statement for resolving directive
context.helper(RESOLVE_DIRECTIVE)
context.directives.add(dir.name)
dirArgs.push(toValidAssetId(dir.name, `directive`))
}
const { loc } = dir
if (dir.exp) dirArgs.push(dir.exp)
if (dir.arg) dirArgs.push(dir.arg)

View File

@@ -28,10 +28,9 @@ export const transformBind: DirectiveTransform = (dir, node, context) => {
}
}
return {
props: createObjectProperty(
arg!,
exp || createSimpleExpression('', true, loc)
),
props: [
createObjectProperty(arg!, exp || createSimpleExpression('', true, loc))
],
needRuntime: false
}
}

View File

@@ -38,7 +38,7 @@ export const transformModel: DirectiveTransform = (dir, node, context) => {
])
: createSimpleExpression('onUpdate:modelValue', true)
return createTransformProps([
const props = [
createObjectProperty(propName, dir.exp!),
createObjectProperty(
eventName,
@@ -48,7 +48,13 @@ export const transformModel: DirectiveTransform = (dir, node, context) => {
` = $event)`
])
)
])
]
if (dir.modifiers.length) {
// TODO add modelModifiers prop
}
return createTransformProps(props)
}
function createTransformProps(props: Property[] = []) {

View File

@@ -69,10 +69,12 @@ export const transformOn: DirectiveTransform = (dir, node, context) => {
}
return {
props: createObjectProperty(
eventName,
dir.exp || createSimpleExpression(`() => {}`, false, loc)
),
props: [
createObjectProperty(
eventName,
dir.exp || createSimpleExpression(`() => {}`, false, loc)
)
],
needRuntime: false
}
}

View File

@@ -6,10 +6,12 @@ import {
export const transformOnce: DirectiveTransform = dir => {
return {
props: createObjectProperty(
createSimpleExpression(`$once`, true, dir.loc),
createSimpleExpression('true', false)
),
props: [
createObjectProperty(
createSimpleExpression(`$once`, true, dir.loc),
createSimpleExpression('true', false)
)
],
needRuntime: false
}
}