vue2 vue3 uniapp (微信小程序) v-model双向绑定

一、核心概念

双向绑定的本质:数据更新视图(v-bind)与视图更新数据(v-on)的结合,v-model 是这一过程的语法糖。
不同框架/版本差异:

  • Vue2 :基于 value 属性和 input 事件,需手动实现多绑定。
  • Vue3 :重构 v-model,支持多参数和自定义属性/事件,灵活度更高。
  • uni-app(微信小程序):兼容 Vue 语法,受小程序原生限制,部分细节不同。

二、分场景详细用法与实例

1. 基础 v-model(单值绑定)

(1)Vue2
  • 逻辑:v-model="val" 等价于 :value="val" @input="val = $event.target.value"
  • 自定义组件需接收 value 属性,触发 input 事件
html 复制代码
<!-- 父组件 -->
<template>
  <Child v-model="msg" />
</template>
<script>
import Child from './Child.vue'
export default {
  components: { Child },
  data() {
    return { msg: 'Vue2 基础绑定' }
  }
}
</script>

<!-- 子组件 Child.vue -->
<template>
  <input :value="value" @input="$emit('input', $event.target.value)" />
</template>
<script>
export default {
  props: {
    value: { type: String, default: '' }
  }
}
</script>
(2)Vue3
  • 逻辑:v-model="val" 等价于 :modelValue="val" @update:modelValue="val = $event"
  • 自定义组件更简洁
html 复制代码
<!-- 父组件 -->
<template>
  <Child v-model="msg" />
</template>
<script setup>
import Child from './Child.vue'
import { ref } from 'vue'
const msg = ref('Vue3 基础绑定')
</script>

<!-- 子组件 Child.vue -->
<template>
  <input :value="modelValue" @input="$emit('update:modelValue', $event.target.value)" />
</template>
<script setup>
defineProps(['modelValue'])
defineEmits(['update:modelValue'])
</script>
(3)uni-app(微信小程序)
  • 兼容 Vue2 语法(默认基于 Vue2,Vue3 需单独配置)
  • 原生组件事件参数在 detail,自定义组件遵循 Vue 规则
html 复制代码
<!-- 父组件(pages/index/index.vue) -->
<template>
  <view>
    <Child v-model="msg" />
    <input v-model="nativeMsg" placeholder="原生输入框" />
  </view>
</template>
<script>
export default {
  data() {
    return { msg: 'uni-app 绑定', nativeMsg: '' }
  },
  components: {
    Child: import('@/components/Child.vue')
  }
}
</script>

<!-- 子组件(components/Child.vue) -->
<template>
  <input :value="value" @input="$emit('input', $event.detail.value)" />
</template>
<script>
export default {
  props: { value: String }
}
</script>

2. 多 v-model(多值双向绑定)

(1)Vue2(手动实现)
  • 需通过 :属性名 + @事件名 实现多个值的绑定
html 复制代码
<!-- 父组件 -->
<template>
  <Child 
    :name="name" @update:name="name = $event"
    :age="age" @update:age="age = $event"
  />
</template>
<script>
export default {
  data() {
    return { name: '张三', age: 20 }
  }
}
</script>

<!-- 子组件 -->
<template>
  <input :value="name" @input="$emit('update:name', $event.target.value)" />
  <input type="number" :value="age" @input="$emit('update:age', $event.target.value)" />
</template>
<script>
export default {
  props: { name: String, age: Number }
}
</script>
(2)Vue3(原生支持多 v-model)
  • 通过 v-model:参数名 实现,无需手动写事件
html 复制代码
<!-- 父组件 -->
<template>
  <Child 
    v-model:name="name"
    v-model:age="age"
  />
</template>
<script setup>
import Child from './Child.vue'
import { ref } from 'vue'
const name = ref('张三')
const age = ref(20)
</script>

<!-- 子组件 -->
<template>
  <input :value="name" @input="$emit('update:name', $event.target.value)" />
  <input type="number" :value="age" @input="$emit('update:age', $event.target.value)" />
</template>
<script setup>
defineProps(['name', 'age'])
defineEmits(['update:name', 'update:age'])
</script>
(3)uni-app(微信小程序)
  • Vue2 版本同 Vue2 手动实现
  • Vue3 版本兼容多 v-model,注意事件参数格式
html 复制代码
<!-- uni-app Vue3 子组件 -->
<template>
  <input :value="name" @input="$emit('update:name', $event.detail.value)" />
  <input type="number" :value="age" @input="$emit('update:age', $event.detail.value)" />
</template>
<script setup>
defineProps(['name', 'age'])
defineEmits(['update:name', 'update:age'])
</script>

3. 自定义属性与事件双向绑定

核心规则:

  • 属性通过 props 接收,事件用 $emit(Vue2)或 defineEmits(Vue3)通知父组件更新。
    实例:Vue3 自定义对象绑定
html 复制代码
<!-- 父组件 -->
<template>
  <Child v-model:user="user" />
</template>
<script setup>
import Child from './Child.vue'
import { ref } from 'vue'
const user = ref({ name: '李四', phone: '13800138000' })
</script>

<!-- 子组件 -->
<template>
  <input 
    :value="user.name" 
    @input="updateUser('name', $event.target.value)"
  />
  <input 
    :value="user.phone" 
    @input="updateUser('phone', $event.target.value)"
  />
</template>
<script setup>
const props = defineProps(['user'])
const emit = defineEmits(['update:user'])

const updateUser = (key, val) => {
  const newUser = { ...props.user, [key]: val }
  emit('update:user', newUser)
}
</script>

uni-app 注意点:

  • 避免使用小程序原生事件名(如 tap、change)作为自定义事件名,防止冲突。
  • 复杂数据建议通过事件更新,不直接绑定到原生组件属性。

三、关键区别汇总表

|---------------|------------------|--------------------------------|---------------------------------------|
| 特性 | Vue2 | Vue3 | uni-app(微信小程序) |
| 基础 v-model 底层 | value + input 事件 | modelValue + update:modelValue | 兼容 Vue2(value + input),原生组件参数在 detail |
| 多 v-model | 手动绑定:属性 + @事件 | 原生支持 v-model: 参数名 | Vue2 版本手动绑定,Vue3 版本兼容 |
| 自定义属性声明 | props 选项 | defineProps 宏 | 同对应 Vue 版本 |
| 自定义事件声明 | 无强制声明,直接 $emit | defineEmits 宏(推荐) | 同对应 Vue 版本,避免原生事件名 |
| 复杂数据绑定 | 支持,但需注意引用类型修改 | 支持,推荐创建新对象 / 数组 | 支持,但避免绑定到原生组件属性 |

四、总结与最佳实践

关键点回顾

  1. 基础绑定差异:Vue2 用 value/input,Vue3 用 modelValue/update:modelValue,uni-app 原生事件参数在 detail。
  2. 多 v-model:Vue3 原生支持 v-model:参数名,Vue2/uni-app Vue2 需手动实现。
  3. 自定义绑定核心:本质是父传子(props)+ 子通知父(emit),不要直接修改 props。

最佳实践建议

  • 优先使用框架原生 v-model 语法,减少手动代码。
  • uni-app 区分原生组件与自定义组件的事件参数格式。
  • 绑定复杂数据时,使用新对象(如解构),避免直接修改 props,确保数据流规范。
相关推荐
白远山7 小时前
上海24小时自助健身房系统软件开发实战指南
java·架构·uni-app·需求分析
StevenLdh9 小时前
第四期 · 云端同步与冲突仲裁:离线可写、多端一致的工程解法
java·微信小程序
溪语流沙9 小时前
Django + Vue电商项目第001讲:开篇|注册登录加增删改查,那不是电商
redis·python·mysql·docker·typescript·django·vue
程序员阿黄9 小时前
基于 Django 与 Vue 3 的智能实验室预约系统设计与实现
后端·python·mysql·django·vue·毕设
.Hypocritical.10 小时前
Vue CLI(vue-cli)和 Vite 超详细对比
vue
m0_4628038810 小时前
会议签到如何设置手写签名?从创建签到到导出签名 PDF 的完整流程
微信小程序
志尊宝1 天前
Vue3 零基础每日笔记(040):Vite 创建 Vue3 + TS 项目——企业标配从这一篇开始
笔记·vue·html·前端开发·软件开发
白远山1 天前
上海24小时自助健身房系统软件开发实战指南:从需求到部署
java·架构·uni-app·需求分析
AI工具人PM产品经理1 天前
零基础微信小程序入门:一个真实项目的里程碑路线图
微信小程序·云开发·学习路线·零基础入门·ai 编程
凤城老人1 天前
从零手写开源私有云盘|Flask+Vue3+Electron全栈网盘,单容器一键部署
python·docker·electron·vue