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

@@ -24,12 +24,16 @@ export const enum DOMErrorCodes {
X_V_HTML_NO_EXPRESSION = ErrorCodes.__EXTEND_POINT__,
X_V_HTML_WITH_CHILDREN,
X_V_TEXT_NO_EXPRESSION,
X_V_TEXT_WITH_CHILDREN
X_V_TEXT_WITH_CHILDREN,
X_V_MODEL_ON_INVALID_ELEMENT,
X_V_MODEL_ARG_ON_ELEMENT
}
export const DOMErrorMessages: { [code: number]: string } = {
[DOMErrorCodes.X_V_HTML_NO_EXPRESSION]: `v-html is missing expression.`,
[DOMErrorCodes.X_V_HTML_WITH_CHILDREN]: `v-html will override element children.`,
[DOMErrorCodes.X_V_TEXT_NO_EXPRESSION]: `v-text is missing expression.`,
[DOMErrorCodes.X_V_TEXT_WITH_CHILDREN]: `v-text will override element children.`
[DOMErrorCodes.X_V_TEXT_WITH_CHILDREN]: `v-text will override element children.`,
[DOMErrorCodes.X_V_MODEL_ON_INVALID_ELEMENT]: `v-model can only be used on <input>, <textarea> and <select> elements.`,
[DOMErrorCodes.X_V_MODEL_ARG_ON_ELEMENT]: `v-model argument is not supported on plain elements.`
}

View File

@@ -5,6 +5,7 @@ import { transformStyle } from './transforms/transformStyle'
import { transformCloak } from './transforms/vCloak'
import { transformVHtml } from './transforms/vHtml'
import { transformVText } from './transforms/vText'
import { transformModel } from './transforms/vModel'
export function compile(
template: string,
@@ -18,6 +19,7 @@ export function compile(
cloak: transformCloak,
html: transformVHtml,
text: transformVText,
model: transformModel, // override compiler-core
...(options.directiveTransforms || {})
}
})

View File

@@ -0,0 +1,15 @@
import { registerRuntimeHelpers } from '@vue/compiler-core'
export const V_MODEL_RADIO = Symbol(__DEV__ ? `vModelRadio` : ``)
export const V_MODEL_CHECKBOX = Symbol(__DEV__ ? `vModelCheckbox` : ``)
export const V_MODEL_TEXT = Symbol(__DEV__ ? `vModelText` : ``)
export const V_MODEL_SELECT = Symbol(__DEV__ ? `vModelSelect` : ``)
export const V_MODEL_DYNAMIC = Symbol(__DEV__ ? `vModelDynamic` : ``)
registerRuntimeHelpers({
[V_MODEL_RADIO]: `vModelRadio`,
[V_MODEL_CHECKBOX]: `vModelCheckbox`,
[V_MODEL_TEXT]: `vModelText`,
[V_MODEL_SELECT]: `vModelSelect`,
[V_MODEL_DYNAMIC]: `vModelDynamic`
})

View File

@@ -19,10 +19,12 @@ export const transformVHtml: DirectiveTransform = (dir, node, context) => {
node.children.length = 0
}
return {
props: createObjectProperty(
createSimpleExpression(`innerHTML`, true, loc),
exp || createSimpleExpression('', true)
),
props: [
createObjectProperty(
createSimpleExpression(`innerHTML`, true, loc),
exp || createSimpleExpression('', true)
)
],
needRuntime: false
}
}

View File

@@ -1 +1,66 @@
// TODO
import {
transformModel as baseTransform,
DirectiveTransform,
ElementTypes,
findProp,
NodeTypes
} from '@vue/compiler-core'
import { createDOMCompilerError, DOMErrorCodes } from '../errors'
import {
V_MODEL_CHECKBOX,
V_MODEL_RADIO,
V_MODEL_SELECT,
V_MODEL_TEXT,
V_MODEL_DYNAMIC
} from '../runtimeHelpers'
export const transformModel: DirectiveTransform = (dir, node, context) => {
const res = baseTransform(dir, node, context)
const { tag, tagType } = node
if (tagType === ElementTypes.ELEMENT) {
if (dir.arg) {
context.onError(
createDOMCompilerError(
DOMErrorCodes.X_V_MODEL_ARG_ON_ELEMENT,
dir.arg.loc
)
)
}
if (tag === 'input' || tag === 'textarea' || tag === 'select') {
let directiveToUse = V_MODEL_TEXT
if (tag === 'input') {
const type = findProp(node, `type`)
if (type) {
if (type.type === NodeTypes.DIRECTIVE) {
// :type="foo"
directiveToUse = V_MODEL_DYNAMIC
} else if (type.value) {
switch (type.value.content) {
case 'radio':
directiveToUse = V_MODEL_RADIO
break
case 'checkbox':
directiveToUse = V_MODEL_CHECKBOX
break
}
}
}
} else if (tag === 'select') {
directiveToUse = V_MODEL_SELECT
}
// inject runtime directive
// by returning the helper symbol via needRuntime
// the import will replaced a resovleDirective call.
res.needRuntime = context.helper(directiveToUse)
} else {
context.onError(
createDOMCompilerError(
DOMErrorCodes.X_V_MODEL_ON_INVALID_ELEMENT,
dir.loc
)
)
}
}
return res
}

View File

@@ -19,10 +19,12 @@ export const transformVText: DirectiveTransform = (dir, node, context) => {
node.children.length = 0
}
return {
props: createObjectProperty(
createSimpleExpression(`textContent`, true, loc),
exp || createSimpleExpression('', true)
),
props: [
createObjectProperty(
createSimpleExpression(`textContent`, true, loc),
exp || createSimpleExpression('', true)
)
],
needRuntime: false
}
}