当前位置: 首页 > article >正文

vue3中自定一个组件并且能够用v-model对自定义组件进行数据的双向绑定

1. 基础用法

在 Vue3 中,v-model 在组件上的使用有了更灵活的方式。默认情况下,v-model 使用 modelValue 作为 prop,update:modelValue 作为事件。

1.1 基本示例

<!-- CustomInput.vue -->
<template>
  <input
    :value="modelValue"
    @input="$emit('update:modelValue', $event.target.value)"
  />
</template>

<script setup>
defineProps(['modelValue'])
defineEmits(['update:modelValue'])
</script>

<!-- 父组件使用 -->
<template>
  <CustomInput v-model="searchText" />
</template>

<script setup>
import { ref } from 'vue'
const searchText = ref('')
</script>

1.2 使用 computed 实现双向绑定

<!-- CustomInput.vue -->
<template>
  <input v-model="inputValue" />
</template>

<script setup>
import { computed } from 'vue'

const props = defineProps(['modelValue'])
const emit = defineEmits(['update:modelValue'])

// 使用计算属性实现双向绑定
const inputValue = computed({
  get() {
    return props.modelValue
  },
  set(value) {
    emit('update:modelValue', value)
  }
})
</script>

2. 自定义 v-model 名称

Vue3 允许我们在同一个组件上使用多个 v-model,每个 v-model 可以有自己的名称。

2.1 单个自定义名称

<!-- CustomField.vue -->
<template>
  <input
    :value="title"
    @input="$emit('update:title', $event.target.value)"
  />
</template>

<script setup>
defineProps(['title'])
defineEmits(['update:title'])
</script>

<!-- 父组件使用 -->
<template>
  <CustomField v-model:title="articleTitle" />
</template>

<script setup>
import { ref } from 'vue'
const articleTitle = ref('默认标题')
</script>

2.2 多个 v-model 绑定

<!-- UserForm.vue -->
<template>
  <div class="form">
    <input
      :value="firstName"
      @input="$emit('update:firstName', $event.target.value)"
    />
    <input
      :value="lastName"
      @input="$emit('update:lastName', $event.target.value)"
    />
  </div>
</template>

<script setup>
defineProps(['firstName', 'lastName'])
defineEmits(['update:firstName', 'update:lastName'])
</script>

<!-- 父组件使用 -->
<template>
  <UserForm
    v-model:firstName="user.firstName"
    v-model:lastName="user.lastName"
  />
</template>

<script setup>
import { reactive } from 'vue'

const user = reactive({
  firstName: 'John',
  lastName: 'Doe'
})
</script>

3. v-model 修饰符

3.1 内置修饰符

<!-- CustomInput.vue -->
<template>
  <input
    :value="modelValue"
    @input="$emit('update:modelValue', $event.target.value)"
  />
</template>

<script setup>
defineProps({
  modelValue: String,
  modelModifiers: { default: () => ({}) }
})
</script>

<!-- 父组件使用 -->
<template>
  <CustomInput v-model.trim="text" />
</template>

3.2 自定义修饰符

<!-- CustomInput.vue -->
<template>
  <input
    :value="modelValue"
    @input="handleInput"
  />
</template>

<script setup>
const props = defineProps({
  modelValue: String,
  modelModifiers: { default: () => ({}) }
})

const emit = defineEmits(['update:modelValue'])

const handleInput = (event) => {
  let value = event.target.value
  // 检查是否应用了 capitalize 修饰符
  if (props.modelModifiers.capitalize) {
    value = value.charAt(0).toUpperCase() + value.slice(1)
  }
  emit('update:modelValue', value)
}
</script>

<!-- 父组件使用 -->
<template>
  <CustomInput v-model.capitalize="text" />
</template>

4. 实际应用示例

4.1 自定义数字输入组件

<!-- NumberInput.vue -->
<template>
  <div class="number-input">
    <button @click="decrease">-</button>
    <input
      type="number"
      :value="modelValue"
      @input="handleInput"
      :step="step"
    />
    <button @click="increase">+</button>
  </div>
</template>

<script setup>
const props = defineProps({
  modelValue: {
    type: Number,
    required: true
  },
  step: {
    type: Number,
    default: 1
  },
  min: {
    type: Number,
    default: -Infinity
  },
  max: {
    type: Number,
    default: Infinity
  }
})

const emit = defineEmits(['update:modelValue'])

const handleInput = (event) => {
  const value = Number(event.target.value)
  if (isValidValue(value)) {
    emit('update:modelValue', value)
  }
}

const increase = () => {
  const newValue = props.modelValue + props.step
  if (isValidValue(newValue)) {
    emit('update:modelValue', newValue)
  }
}

const decrease = () => {
  const newValue = props.modelValue - props.step
  if (isValidValue(newValue)) {
    emit('update:modelValue', newValue)
  }
}

const isValidValue = (value) => {
  return value >= props.min && value <= props.max
}
</script>

<!-- 父组件使用 -->
<template>
  <NumberInput
    v-model="quantity"
    :step="1"
    :min="0"
    :max="100"
  />
</template>

<script setup>
import { ref } from 'vue'
const quantity = ref(1)
</script>

4.2 颜色选择器组件

<!-- ColorPicker.vue -->
<template>
  <div class="color-picker">
    <div
      class="color-preview"
      :style="{ backgroundColor: modelValue }"
    ></div>
    <input
      type="color"
      :value="modelValue"
      @input="$emit('update:modelValue', $event.target.value)"
    />
    <input
      type="text"
      :value="modelValue"
      @input="handleInput"
      placeholder="#000000"
    />
  </div>
</template>

<script setup>
const props = defineProps({
  modelValue: {
    type: String,
    default: '#000000'
  }
})

const emit = defineEmits(['update:modelValue'])

const handleInput = (event) => {
  const value = event.target.value
  // 验证是否为有效的颜色值
  if (/^#[0-9A-Fa-f]{6}$/.test(value)) {
    emit('update:modelValue', value)
  }
}
</script>

<!-- 父组件使用 -->
<template>
  <ColorPicker v-model="themeColor" />
</template>

<script setup>
import { ref } from 'vue'
const themeColor = ref('#42b883')
</script>

5. 最佳实践

  1. 命名规范

    • 使用语义化的 prop 名称
    • 保持事件名称与 prop 名称的一致性
    • 使用 update: 前缀作为事件名称
  2. 类型检查

    • 为 props 定义明确的类型
    • 在必要时添加自定义验证
    • 处理无效输入
  3. 值的验证

    • 在更新值之前进行验证
    • 提供适当的错误反馈
    • 实现合理的默认值处理
  4. 性能优化

    • 避免不必要的值更新
    • 使用计算属性优化复杂逻辑
    • 合理使用防抖和节流

http://www.kler.cn/a/518674.html

相关文章:

  • 【大数据】机器学习----------强化学习机器学习阶段尾声
  • 深度学习 Pytorch 单层神经网络
  • 在Rust应用中访问.ini格式的配置文件
  • CNN-BiLSTM卷积双向长短期记忆神经网络时间序列预测(Matlab完整源码和数据)
  • npm和webpack学习
  • 大厂案例——腾讯蓝鲸DevOps类应用的设计与实践
  • 如何有效利用数据采集HTTP代理
  • ASP.NET代码审计 SQL注入篇(简单记录)
  • 2024年终总结:技术成长与突破之路
  • CCF开源发展委员会开源供应链安全工作组2025年第1期技术研讨会顺利举行
  • FastDFS的安装及使用
  • LabVIEW心音心电同步采集与实时播放
  • [c语言日寄]结构体的使用及其拓展
  • Arcgis国产化替代:Bigemap Pro正式发布
  • OpenHarmony5.0 AVPlayer新特性开发指导(二)
  • 基于本地事务表+MQ实现分布式事务
  • 计算机工程:解锁未来科技之门!
  • Spring Boot Actuator 集成 Micrometer(官网文档解读)
  • 警企联动齐发力、共筑反诈“防护墙”
  • 2025美赛B题-问题B:管理可持续旅游
  • 如何使用 MySQL 的 EXPLAIN 语句进行查询分析?
  • 数据结构测试题2
  • day1代码练习
  • 在 DevOps 实践中,如何构建自动化的持续集成和持续交付(CI/CD)管道,以提高开发和测试效率?
  • 浅谈Redis
  • c语言分支和循环