vue3 实现自定义 v-model

在 vue 中,form 表单输入可以通过 v-model 实现双向数据绑定,例如:
<input v-model="text" />
{{text}}

在表单中输入时,页面展示的 data-text 也会相应改变

如果是封装的通用输入表单,一般会使用 prop+emit 来实现父子组件数据传递
如:封装一个数字输入框
子组件: child.vue
<template>
<input :value="modelValue" @input="inputValue" type="number" />
</template>

<script>
export default {
  props: {
    modelValue: {
      type: String,
      default: "",
    },
  },
  setup(props, { emit }) {
    const inputValue = (e) => {
      const value = e.target.value;
      emit("updatemodelValue", value);
    };
    return {
      inputValue,
    };
  },
};
</script>
父组件: parent.vue
<template>
  <div>
    <number-input
      :modelValue="modelValue"
      @updateModelValue="updateModelValue"
    />
    <div>modelValue: {{ modelValue }}</div>
  </div>
</template>

<script>
import { reactive, toRefs } from "vue";
import NumberInput from "../components/child.vue";
export default {
  components: {
    NumberInput,
  },
  setup() {
    const value = reactive({
      modelValue: "",
    });

    const updateModelValue = (val) => {
      value.modelValue = val;
    };
    return {
      updateModelValue,
      ...toRefs(value),
    };
  },
};
</script>

这样实现父子数据的双向传递,那可不可以直接在使用子组件时用 v-model 实现这些效果呢?vue3 提供了 v-model 的自定义事件支持.直接看实现步骤
子组件: child2.vue
<template>
  <div>
    name: <input :value="modelValue" @input="inputValue" type="number" /> title:
    <input :value="titleValue" @input="inputTilte" />
  </div>
</template>

<script>
export default {
  props: {
    modelValue: {
      type: String,
      default: "",
    },
    titleValue: {
      type: String,
      default: "",
    },
  },
  setup(props, { emit }) {
    const inputValue = (e) => {
      const value = e.target.value;
      emit("update:modelValue", value);
    };
    const inputTilte = (e) => {
      emit("update:titleValue", e.target.value);
    };
    return {
      inputValue,
      inputTilte,
    };
  },
};
</script>
父组件: parent.vue
<template>
  <div>
    <h3>v-model实现</h3>
    <my-input v-model="inputValue" v-model:titleValue="title" />
    <div>inputValue: {{ inputValue }}</div>
    <div>titleValue: {{ title }}</div>
  </div>
</template>

<script>
import { reactive, toRefs } from "vue";
import MyInput from "../components/child2.vue";
export default {
  components: {
    MyInput,
  },
  setup() {
    const value = reactive({
      inputValue: "",
      title: "",
    });

    return {
      ...toRefs(value),
    };
  },
};
</script>
效果:

 

v-model 可以有多个,默认的名称是 modelValue 与 update:titleValue
如果是其他名字,在 v-model 后面加上名称的后缀 v-model:titleValue + update:titleValue

这样写帮我们省去了父组件中 emit 的接收事件,vue 帮我们声明了这个事件
posted @ 2022-12-02 16:39  潇湘羽西  阅读(3327)  评论(0编辑  收藏  举报