فهرست منبع

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

Evan You 5 سال پیش
والد
کامیت
fe5428db12

+ 33 - 1
packages/compiler-ssr/__tests__/ssrVModel.spec.ts

@@ -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)
       .toMatchInlineSnapshot(`
       "const { ssrLooseContain: _ssrLooseContain, ssrRenderAttrs: _ssrRenderAttrs } = require(\\"@vue/server-renderer\\")
@@ -81,6 +81,38 @@ describe('ssr: v-model', () => {
         }></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>', () => {

+ 19 - 1
packages/compiler-ssr/src/transforms/ssrTransformElement.ts

@@ -25,7 +25,8 @@ import {
   isBindKey,
   createSequenceExpression,
   InterpolationNode,
-  isStaticExp
+  isStaticExp,
+  AttributeNode
 } from '@vue/compiler-dom'
 import {
   escapeHtml,
@@ -159,6 +160,10 @@ export const ssrTransformElement: NodeTransform = (node, context) => {
 
     for (let i = 0; i < node.props.length; 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
       if (prop.type === NodeTypes.DIRECTIVE) {
         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(
   node: PlainElementNode,
   prop: DirectiveNode

+ 28 - 11
packages/compiler-ssr/src/transforms/ssrVModel.ts

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