浏览代码

fix(compiler-sfc): support template literal as defineModel name (#14622)

close #14621
bab 4 周之前
父节点
当前提交
bd7eef0161

+ 44 - 0
packages/compiler-sfc/__tests__/compileScript/__snapshots__/defineModel.spec.ts.snap

@@ -166,6 +166,50 @@ return { count }
 }"
 `;
 
+exports[`defineModel() > w/ template literal name 1`] = `
+"import { useModel as _useModel } from 'vue'
+
+export default {
+  props: {
+    "x": { default: 100 },
+    "xModifiers": {},
+    "y": { default: 200 },
+    "yModifiers": {},
+  },
+  emits: ["update:x", "update:y"],
+  setup(__props, { expose: __expose }) {
+  __expose();
+
+      const x = _useModel(__props, \`x\`)
+      const y = _useModel(__props, \`y\`)
+      
+return { x, y }
+}
+
+}"
+`;
+
+exports[`defineModel() > w/ template literal name with expressions falls back to modelValue 1`] = `
+"import { useModel as _useModel } from 'vue'
+const name = 'x'
+      
+export default {
+  props: {
+    "modelValue": \`\${name}\`,
+    "modelModifiers": {},
+  },
+  emits: ["update:modelValue"],
+  setup(__props, { expose: __expose }) {
+  __expose();
+
+      const m = _useModel(__props, "modelValue", \`\${name}\`)
+      
+return { name, m }
+}
+
+}"
+`;
+
 exports[`defineModel() > w/ types, basic usage 1`] = `
 "import { useModel as _useModel, defineComponent as _defineComponent } from 'vue'
 

+ 37 - 0
packages/compiler-sfc/__tests__/compileScript/defineModel.spec.ts

@@ -36,6 +36,43 @@ describe('defineModel()', () => {
     })
   })
 
+  test('w/ template literal name', () => {
+    const { content, bindings } = compile(
+      `
+      <script setup>
+      const x = defineModel(\`x\`, { default: 100 })
+      const y = defineModel(\`y\`, { default: 200 })
+      </script>
+      `,
+    )
+    assertCode(content)
+    expect(content).toMatch('"x": { default: 100 },')
+    expect(content).toMatch('"y": { default: 200 },')
+    expect(content).toMatch('emits: ["update:x", "update:y"],')
+    expect(content).toMatch('const x = _useModel(__props, `x`)')
+    expect(content).toMatch('const y = _useModel(__props, `y`)')
+    expect(content).not.toMatch('defineModel')
+
+    expect(bindings).toStrictEqual({
+      x: BindingTypes.SETUP_REF,
+      y: BindingTypes.SETUP_REF,
+    })
+  })
+
+  test('w/ template literal name with expressions falls back to modelValue', () => {
+    const { content } = compile(
+      `
+      <script setup>
+      const name = 'x'
+      const m = defineModel(\`\${name}\`)
+      </script>
+      `,
+    )
+    assertCode(content)
+    expect(content).toMatch('"modelValue":')
+    expect(content).toMatch('_useModel(__props, "modelValue",')
+  })
+
   test('w/ defineProps and defineEmits', () => {
     const { content, bindings } = compile(
       `

+ 6 - 2
packages/compiler-sfc/src/script/defineModel.ts

@@ -29,9 +29,13 @@ export function processDefineModel(
   let modelName: string
   let options: Node | undefined
   const arg0 = node.arguments[0] && unwrapTSNode(node.arguments[0])
-  const hasName = arg0 && arg0.type === 'StringLiteral'
+  const hasName =
+    arg0 &&
+    (arg0.type === 'StringLiteral' ||
+      (arg0.type === 'TemplateLiteral' && arg0.expressions.length === 0))
   if (hasName) {
-    modelName = arg0.value
+    modelName =
+      arg0.type === 'StringLiteral' ? arg0.value : arg0.quasis[0].value.cooked!
     options = node.arguments[1]
   } else {
     modelName = 'modelValue'