fix(compiler-ssr): handle v-model checkbox with true-value binding

This commit is contained in:
Evan You 2020-12-01 12:43:59 -05:00
parent 48f00c0f1b
commit fe5428db12
3 changed files with 80 additions and 13 deletions

View File

@ -49,7 +49,7 @@ describe('ssr: v-model', () => {
`) `)
}) })
test('<input type="checkbox"', () => { test('<input type="checkbox">', () => {
expect(compileWithWrapper(`<input type="checkbox" v-model="bar">`).code) expect(compileWithWrapper(`<input type="checkbox" v-model="bar">`).code)
.toMatchInlineSnapshot(` .toMatchInlineSnapshot(`
"const { ssrLooseContain: _ssrLooseContain, ssrRenderAttrs: _ssrRenderAttrs } = require(\\"@vue/server-renderer\\") "const { ssrLooseContain: _ssrLooseContain, ssrRenderAttrs: _ssrRenderAttrs } = require(\\"@vue/server-renderer\\")
@ -81,6 +81,38 @@ describe('ssr: v-model', () => {
}></div>\`) }></div>\`)
}" }"
`) `)
expect(
compileWithWrapper(
`<input type="checkbox" :true-value="foo" :false-value="bar" v-model="baz">`
).code
).toMatchInlineSnapshot(`
"const { ssrLooseEqual: _ssrLooseEqual, ssrRenderAttrs: _ssrRenderAttrs } = require(\\"@vue/server-renderer\\")
return function ssrRender(_ctx, _push, _parent, _attrs) {
_push(\`<div\${
_ssrRenderAttrs(_attrs)
}><input type=\\"checkbox\\"\${
(_ssrLooseEqual(_ctx.baz, _ctx.foo)) ? \\" checked\\" : \\"\\"
}></div>\`)
}"
`)
expect(
compileWithWrapper(
`<input type="checkbox" true-value="foo" false-value="bar" v-model="baz">`
).code
).toMatchInlineSnapshot(`
"const { ssrLooseEqual: _ssrLooseEqual, ssrRenderAttrs: _ssrRenderAttrs } = require(\\"@vue/server-renderer\\")
return function ssrRender(_ctx, _push, _parent, _attrs) {
_push(\`<div\${
_ssrRenderAttrs(_attrs)
}><input type=\\"checkbox\\"\${
(_ssrLooseEqual(_ctx.baz, \\"foo\\")) ? \\" checked\\" : \\"\\"
}></div>\`)
}"
`)
}) })
test('<textarea>', () => { test('<textarea>', () => {

View File

@ -25,7 +25,8 @@ import {
isBindKey, isBindKey,
createSequenceExpression, createSequenceExpression,
InterpolationNode, InterpolationNode,
isStaticExp isStaticExp,
AttributeNode
} from '@vue/compiler-dom' } from '@vue/compiler-dom'
import { import {
escapeHtml, escapeHtml,
@ -159,6 +160,10 @@ export const ssrTransformElement: NodeTransform = (node, context) => {
for (let i = 0; i < node.props.length; i++) { for (let i = 0; i < node.props.length; i++) {
const prop = node.props[i] const prop = node.props[i]
// ignore true-value/false-value on input
if (node.tag === 'input' && isTrueFalseValue(prop)) {
continue
}
// special cases with children override // special cases with children override
if (prop.type === NodeTypes.DIRECTIVE) { if (prop.type === NodeTypes.DIRECTIVE) {
if (prop.name === 'html' && prop.exp) { if (prop.name === 'html' && prop.exp) {
@ -306,6 +311,19 @@ export const ssrTransformElement: NodeTransform = (node, context) => {
} }
} }
function isTrueFalseValue(prop: DirectiveNode | AttributeNode) {
if (prop.type === NodeTypes.DIRECTIVE) {
return (
prop.name === 'bind' &&
prop.arg &&
isStaticExp(prop.arg) &&
(prop.arg.content === 'true-value' || prop.arg.content === 'false-value')
)
} else {
return prop.name === 'true-value' || prop.name === 'false-value'
}
}
function isTextareaWithValue( function isTextareaWithValue(
node: PlainElementNode, node: PlainElementNode,
prop: DirectiveNode prop: DirectiveNode

View File

@ -71,19 +71,36 @@ export const ssrTransformModel: DirectiveTransform = (dir, node, context) => {
] ]
break break
case 'checkbox': case 'checkbox':
res.props = [ const trueValueBinding = findProp(node, 'true-value')
createObjectProperty( if (trueValueBinding) {
`checked`, const trueValue =
createConditionalExpression( trueValueBinding.type === NodeTypes.ATTRIBUTE
createCallExpression(`Array.isArray`, [model]), ? JSON.stringify(trueValueBinding.value!.content)
createCallExpression(context.helper(SSR_LOOSE_CONTAIN), [ : trueValueBinding.exp!
res.props = [
createObjectProperty(
`checked`,
createCallExpression(context.helper(SSR_LOOSE_EQUAL), [
model, model,
value trueValue
]), ])
model
) )
) ]
] } else {
res.props = [
createObjectProperty(
`checked`,
createConditionalExpression(
createCallExpression(`Array.isArray`, [model]),
createCallExpression(context.helper(SSR_LOOSE_CONTAIN), [
model,
value
]),
model
)
)
]
}
break break
case 'file': case 'file':
context.onError( context.onError(