Skip to content

测试 v-model

当编写依赖于v-model交互的组件时(更新:modelValue事件),你需要处理事件和props

查看一些社区解决方案的“vmodel 集成”讨论。

检查VueJS VModel事件文档

简单的例子

这里有一个简单的 Editor 组件:

js
const Editor = {
  props: {
    label: String,
    modelValue: String,
  },
  emits: ["update:modelValue"],
  template: `<div>
    <label>{{label}}</label>
    <input :value="modelValue" @input="$emit('update:modelValue', $event.target.value)">
  </div>`,
};
const Editor = {
  props: {
    label: String,
    modelValue: String,
  },
  emits: ["update:modelValue"],
  template: `<div>
    <label>{{label}}</label>
    <input :value="modelValue" @input="$emit('update:modelValue', $event.target.value)">
  </div>`,
};

这个组件的行为就像一个input组件:

js
const App {
  components: {
    Editor
  },
  template: `<editor v-model="text" label="test" />`,
  data(){
    return {
      text: 'test'
    }
  }
}
const App {
  components: {
    Editor
  },
  template: `<editor v-model="text" label="test" />`,
  data(){
    return {
      text: 'test'
    }
  }
}

现在,当我们输入input时,它将更新组件上的文本。

要测试此行为:

js
test("modelValue should be updated", async () => {
  const wrapper = mount(Editor, {
    props: {
      modelValue: "initialText",
      "onUpdate:modelValue": (e) => wrapper.setProps({ modelValue: e }),
    },
  });

  await wrapper.find("input").setValue("test");
  expect(wrapper.props("modelValue")).toBe("test");
});
test("modelValue should be updated", async () => {
  const wrapper = mount(Editor, {
    props: {
      modelValue: "initialText",
      "onUpdate:modelValue": (e) => wrapper.setProps({ modelValue: e }),
    },
  });

  await wrapper.find("input").setValue("test");
  expect(wrapper.props("modelValue")).toBe("test");
});

多个 v-model

在某些情况下,我们可以有多个针对特定属性的v-model

例如Money Editor,我们可以有currencymodelValue属性。

js
const MoneyEditor = {
  template: `<div> 
    <input :value="currency" @input="$emit('update:currency', $event.target.value)"/>
    <input :value="modelValue" type="number" @input="$emit('update:modelValue', $event.target.value)"/>
  </div>`,
  props: ["currency", "modelValue"],
  emits: ["update:currency", "update:modelValue"],
};
const MoneyEditor = {
  template: `<div> 
    <input :value="currency" @input="$emit('update:currency', $event.target.value)"/>
    <input :value="modelValue" type="number" @input="$emit('update:modelValue', $event.target.value)"/>
  </div>`,
  props: ["currency", "modelValue"],
  emits: ["update:currency", "update:modelValue"],
};

我们可以通过以下方式进行测试:

js
test("modelValue and currency should be updated", async () => {
  const wrapper = mount(MoneyEditor, {
    props: {
      modelValue: "initialText",
      "onUpdate:modelValue": (e) => wrapper.setProps({ modelValue: e }),
      currency: "$",
      "onUpdate:currency": (e) => wrapper.setProps({ currency: e }),
    },
  });

  const [currencyInput, modelValueInput] = wrapper.findAll("input");
  await modelValueInput.setValue("test");
  await currencyInput.setValue("£");

  expect(wrapper.props("modelValue")).toBe("test");
  expect(wrapper.props("currency")).toBe("£");
});
test("modelValue and currency should be updated", async () => {
  const wrapper = mount(MoneyEditor, {
    props: {
      modelValue: "initialText",
      "onUpdate:modelValue": (e) => wrapper.setProps({ modelValue: e }),
      currency: "$",
      "onUpdate:currency": (e) => wrapper.setProps({ currency: e }),
    },
  });

  const [currencyInput, modelValueInput] = wrapper.findAll("input");
  await modelValueInput.setValue("test");
  await currencyInput.setValue("£");

  expect(wrapper.props("modelValue")).toBe("test");
  expect(wrapper.props("currency")).toBe("£");
});