Vue3 v-model:灵活的双向数据绑定


v-model 是 Vue.js 中用于实现双向数据绑定的指令,它使得在表单元素和组件之间进行数据的双向同步变得非常简单。在 Vue3 中,v-model 经历了一些改进,提供了更灵活的用法。本文将介绍 Vue3 中 v-model 的新特性以及如何使用它来实现双向数据绑定。

一、v-model基本用法

在vue2中一个组件上只能挂载一个v-model,而vue3中对v-model进行了优化,可写多个v-model,用自定义修饰符进行识别。


在普通组件上使用:只有作为表单内的元素属性时才会生效 如: input 、radio 、checkbox

<input v-model="searchText" />
//相当于
<input
  :value="searchText"
  @input="searchText = $event.target.value"
/>

在自定义组件上使用:

<CustomInput v-model="searchText"/>
//相当于
<CustomInput
  :model-value="searchText"
  @update:model-value="newValue => searchText = newValue"
/>

对自定义组件v-model接收

  • 默认绑定接收
//父组件
<CustomInput v-model="searchText"/>

//子组件接收
interface IProps {
  modelValue: boolean;
}
const props = withDefaults(defineProps<IProps>(), {
  modelValue: true,
});

const emit = defineEmits(["update:modelValue"]);

  • 自定义名称接收
//父组件
<CustomInput v-model:textModel="textModel"/>

//子组件接收
interface IProps {
  textModel: string;
}
const props = withDefaults(defineProps<IProps>(), {
  textModel: '',
});

const emit = defineEmits(["update:textModel"]);

  • 自定义修饰符
//父组件
<Address v-model="showModal" v-model:textModel.addPrefix="textModel" />


//子组件
//自定义的修饰符需要在子组件中用 props 接收 modelModifiers 对象,这个对象下面会有自定义属性,值为 true
const props = (defineProps<{
	textModelModifiers:{
		addPrefix:boolean
	}
}>();
cons

二、v-model 注意事项

在子组件中不要直接修改父组件传过来的props,如下,直接使用会报以下的错误
在这里插入图片描述

在这里插入图片描述
请注意这个错误在版本3.2.45上开始出现。
对于实现模式,正如文档中所指出的,props在组件中应该被认为是只读的,Vue在版本3.2.45之前没有充分地执行它。


三、v-model和computed结合

针对上面案例中出现的问题,我们明白了在子组件不能直接修改父组件的传过来的值。那如何更好的实现双向数据绑定呢,这个时候我们可以结合computed一起使用。


如下,是关于v-model和computed结合使用的例子

效果图

v-model数据双向绑定


父组件实现代码

//父组件
<template>
  <n-message-provider>
    <button @click="handleEdit">编辑</button>
    <div>个人简介:{{ textModel }}</div>
    <Modal v-model="showModal" v-model:textModel"textModel" />
  </n-message-provider>
</template>
<script setup lang="ts">
import { ref } from "vue";
import { NMessageProvider } from "naive-ui";
import Modal from "@/views/Modal /Modal.vue";
const showModal = ref(false);
const textModel = ref("");

const handleEdit = () => {
  showModal.value = true;
};
</script>

<style scoped lang="scss"></style>

在上面代码中引入了modal子组件,并向子组件绑定了默认的v-model和自定义名称的v-model:textModel


子组件实现代码

<template>
  <n-modal
    v-model:show="model_value"
    preset="card"
    :title="title"
    size="small"
    class="modal-dialog-wrapper"
    header-style="padding: 10px 20px"
    :bordered="false"
    :segmented="segmented"
    display-directive="show"
    :style="{ width: contentWidth }"
  >
    <div class="content" :style="{ height: '60vh', height: contentHeight }">
      <n-scrollbar class="pl-5 pr-5">
        <p>个人简介:</p>
        <n-input
          v-model:value="text_model"
          type="textarea"
          placeholder="请输入个人简介"
          rows="8"
        />
      </n-scrollbar>
    </div>
    <template #footer>
      <div class="footer-wrap">
        <n-space>
          <n-button type="primary" size="small" @click="onConfirm"
            >确定</n-button
          >
        </n-space>
      </div>
    </template>
  </n-modal>
</template>

<script setup lang="ts">
import { ref, computed } from "vue";
import { NModal, NScrollbar, NSpace, NButton, NInput } from "naive-ui";
interface IProps {
  title?: string;
  contentHeight?: string;
  contentWidth?: string;
  modelValue: boolean;
  textModel?: string;
  textModelModifiers: {
    addPrefix: boolean;
  };
}
const props = withDefaults(defineProps<IProps>(), {
  title: "消息",
  contentHeight: "30vh",
  contentWidth: "600px",
  modelValue: true,
});
const segmented = ref({
  content: "soft",
  footer: "soft",
});

const emit = defineEmits(["update:modelValue", "update:textModel"]);
const model_value = computed({
  get() {
    return props.modelValue;
  },
  set(value) {
    emit("update:modelValue", value);
  },
});
const text_model = computed({
  get() {
    return props.textModel;
  },
  set(value) {
    emit("update:textModel", value);
  },
});
const onConfirm = () => {
  model_value.value = false;
};
</script>
<style scoped>
.footer-wrap {
  display: flex;
  justify-content: flex-end;
}
</style>

在上面子组件中,为了实现双向数据绑定,使用computed将可写属性与 gettersetter 一起使用。该方法应返回属性,并且该方法应发出相应的事件。

四、总结

Vue3 中的 v-model 经历了一些改进,提供了更灵活的用法来实现双向数据绑定。除了原生的表单元素外,v-model 现在可以应用于任意组件,并允许我们自定义 prop 和事件名称。

使用 Vue3 的 v-model,我们可以更加方便地实现组件之间的数据双向同步,减少了手动处理数据绑定的工作量。

  • 34
    点赞
  • 32
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值