fix(v-model): should use dynamic directive on input with dynamic v-bind
This commit is contained in:
parent
ae92925011
commit
1f2de9e232
@ -205,6 +205,17 @@ export function findProp(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function hasDynamicKeyVBind(node: ElementNode): boolean {
|
||||||
|
return node.props.some(
|
||||||
|
p =>
|
||||||
|
p.type === NodeTypes.DIRECTIVE &&
|
||||||
|
p.name === 'bind' &&
|
||||||
|
(!p.arg || // v-bind="obj"
|
||||||
|
p.arg.type !== NodeTypes.SIMPLE_EXPRESSION || // v-bind:[_ctx.foo]
|
||||||
|
!p.arg.isStatic) // v-bind:[foo]
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
export function createBlockExpression(
|
export function createBlockExpression(
|
||||||
blockExp: BlockCodegenNode,
|
blockExp: BlockCodegenNode,
|
||||||
context: TransformContext
|
context: TransformContext
|
||||||
|
@ -1,5 +1,42 @@
|
|||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
|
exports[`compiler: transform v-model input w/ dynamic v-bind 1`] = `
|
||||||
|
"const _Vue = Vue
|
||||||
|
|
||||||
|
return function render() {
|
||||||
|
with (this) {
|
||||||
|
const { vModelDynamic: _vModelDynamic, mergeProps: _mergeProps, createVNode: _createVNode, withDirectives: _withDirectives, createBlock: _createBlock, openBlock: _openBlock } = _Vue
|
||||||
|
|
||||||
|
return (_openBlock(), _withDirectives(_createBlock(\\"input\\", _mergeProps(obj, {
|
||||||
|
modelValue: model,
|
||||||
|
\\"onUpdate:modelValue\\": $event => (model = $event)
|
||||||
|
}), null, 16 /* FULL_PROPS */, [\\"modelValue\\", \\"onUpdate:modelValue\\"]), [
|
||||||
|
[_vModelDynamic, model]
|
||||||
|
]))
|
||||||
|
}
|
||||||
|
}"
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`compiler: transform v-model input w/ dynamic v-bind 2`] = `
|
||||||
|
"const _Vue = Vue
|
||||||
|
|
||||||
|
return function render() {
|
||||||
|
with (this) {
|
||||||
|
const { vModelDynamic: _vModelDynamic, createVNode: _createVNode, withDirectives: _withDirectives, resolveDirective: _resolveDirective, createBlock: _createBlock, openBlock: _openBlock } = _Vue
|
||||||
|
|
||||||
|
const _directive_bind = _resolveDirective(\\"bind\\")
|
||||||
|
|
||||||
|
return (_openBlock(), _withDirectives(_createBlock(\\"input\\", {
|
||||||
|
modelValue: model,
|
||||||
|
\\"onUpdate:modelValue\\": $event => (model = $event)
|
||||||
|
}, null, 8 /* PROPS */, [\\"modelValue\\", \\"onUpdate:modelValue\\"]), [
|
||||||
|
[_directive_bind, val, key],
|
||||||
|
[_vModelDynamic, model]
|
||||||
|
]))
|
||||||
|
}
|
||||||
|
}"
|
||||||
|
`;
|
||||||
|
|
||||||
exports[`compiler: transform v-model modifiers .lazy 1`] = `
|
exports[`compiler: transform v-model modifiers .lazy 1`] = `
|
||||||
"const _Vue = Vue
|
"const _Vue = Vue
|
||||||
|
|
||||||
|
@ -63,6 +63,19 @@ describe('compiler: transform v-model', () => {
|
|||||||
expect(generate(root).code).toMatchSnapshot()
|
expect(generate(root).code).toMatchSnapshot()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test('input w/ dynamic v-bind', () => {
|
||||||
|
const root = transformWithModel('<input v-bind="obj" v-model="model" />')
|
||||||
|
|
||||||
|
expect(root.helpers).toContain(V_MODEL_DYNAMIC)
|
||||||
|
expect(generate(root).code).toMatchSnapshot()
|
||||||
|
|
||||||
|
const root2 = transformWithModel(
|
||||||
|
'<input v-bind:[key]="val" v-model="model" />'
|
||||||
|
)
|
||||||
|
expect(root2.helpers).toContain(V_MODEL_DYNAMIC)
|
||||||
|
expect(generate(root2).code).toMatchSnapshot()
|
||||||
|
})
|
||||||
|
|
||||||
test('simple expression for select', () => {
|
test('simple expression for select', () => {
|
||||||
const root = transformWithModel('<select v-model="model" />')
|
const root = transformWithModel('<select v-model="model" />')
|
||||||
|
|
||||||
|
@ -3,7 +3,8 @@ import {
|
|||||||
DirectiveTransform,
|
DirectiveTransform,
|
||||||
ElementTypes,
|
ElementTypes,
|
||||||
findProp,
|
findProp,
|
||||||
NodeTypes
|
NodeTypes,
|
||||||
|
hasDynamicKeyVBind
|
||||||
} from '@vue/compiler-core'
|
} from '@vue/compiler-core'
|
||||||
import { createDOMCompilerError, DOMErrorCodes } from '../errors'
|
import { createDOMCompilerError, DOMErrorCodes } from '../errors'
|
||||||
import {
|
import {
|
||||||
@ -75,6 +76,10 @@ export const transformModel: DirectiveTransform = (dir, node, context) => {
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else if (hasDynamicKeyVBind(node)) {
|
||||||
|
// element has bindings with dynamic keys, which can possibly contain
|
||||||
|
// "type".
|
||||||
|
directiveToUse = V_MODEL_DYNAMIC
|
||||||
} else {
|
} else {
|
||||||
// text type
|
// text type
|
||||||
__DEV__ && checkDuplicatedValue()
|
__DEV__ && checkDuplicatedValue()
|
||||||
|
@ -19,7 +19,8 @@ import {
|
|||||||
JSChildNode,
|
JSChildNode,
|
||||||
ArrayExpression,
|
ArrayExpression,
|
||||||
createAssignmentExpression,
|
createAssignmentExpression,
|
||||||
TextNode
|
TextNode,
|
||||||
|
hasDynamicKeyVBind
|
||||||
} from '@vue/compiler-dom'
|
} from '@vue/compiler-dom'
|
||||||
import { escapeHtml, isBooleanAttr, isSSRSafeAttrName } from '@vue/shared'
|
import { escapeHtml, isBooleanAttr, isSSRSafeAttrName } from '@vue/shared'
|
||||||
import { createSSRCompilerError, SSRErrorCodes } from '../errors'
|
import { createSSRCompilerError, SSRErrorCodes } from '../errors'
|
||||||
@ -46,14 +47,7 @@ export const ssrTransformElement: NodeTransform = (node, context) => {
|
|||||||
// v-bind="obj" or v-bind:[key] can potentially overwrite other static
|
// v-bind="obj" or v-bind:[key] can potentially overwrite other static
|
||||||
// attrs and can affect final rendering result, so when they are present
|
// attrs and can affect final rendering result, so when they are present
|
||||||
// we need to bail out to full `renderAttrs`
|
// we need to bail out to full `renderAttrs`
|
||||||
const hasDynamicVBind = node.props.some(
|
const hasDynamicVBind = hasDynamicKeyVBind(node)
|
||||||
p =>
|
|
||||||
p.type === NodeTypes.DIRECTIVE &&
|
|
||||||
p.name === 'bind' &&
|
|
||||||
(!p.arg || // v-bind="obj"
|
|
||||||
p.arg.type !== NodeTypes.SIMPLE_EXPRESSION || // v-bind:[_ctx.foo]
|
|
||||||
!p.arg.isStatic) // v-bind:[foo]
|
|
||||||
)
|
|
||||||
if (hasDynamicVBind) {
|
if (hasDynamicVBind) {
|
||||||
const { props } = buildProps(node, context, node.props, true /* ssr */)
|
const { props } = buildProps(node, context, node.props, true /* ssr */)
|
||||||
if (props) {
|
if (props) {
|
||||||
|
@ -96,7 +96,8 @@ export const ssrTransformModel: DirectiveTransform = (dir, node, context) => {
|
|||||||
checkDuplicatedValue()
|
checkDuplicatedValue()
|
||||||
node.children = [createInterpolation(model, model.loc)]
|
node.children = [createInterpolation(model, model.loc)]
|
||||||
} else if (node.tag === 'select') {
|
} else if (node.tag === 'select') {
|
||||||
// TODO
|
// NOOP
|
||||||
|
// select relies on client-side directive to set initial selected state.
|
||||||
} else {
|
} else {
|
||||||
context.onError(
|
context.onError(
|
||||||
createDOMCompilerError(
|
createDOMCompilerError(
|
||||||
|
Loading…
Reference in New Issue
Block a user