vue3学习记录-v-model

1.疑问

像那种原生标签,例如input、textarea 及 select上使用v-model,会创建双向数据绑定。那像那种自定义的组件v-model是怎么实现双向绑定的呢。

2 用法

2.1底层原理

一个名为 modelValue 的 prop,本地 ref 的值与其同步;
一个名为 update:modelValue 的事件,当本地 ref 的值发生变更时触发。

//父组件
<script setup>
import A from './components/A.vue';
import { ref } from 'vue';
const countModel = ref(0);
</script>
<template>
  <div class="container">
    <p>countModel:{{ countModel }}</p>
    <A v-model="countModel"></A>
    <B v-model="countModel1"></B>
  </div>
</template>


//子组件
<template>
<input type="text" :value="modelValue" @input="inputChange">
</template>
<script setup>
defineProps({
  modelValue:String
})
const inputChange =(e) =>{
  console.log(e.target.value)
  emit('update:modelValue',e.target.value)
}
const emit = defineEmits(['update:modelValue'])
</script>

其实还是把组件向下传的值,子组件接受绑定在input、textarea 及 select上,改变时再emit出来,父组件接收后又再改变自己的值。
父组件中的 v-model=“foo” 将被编译为:

<A
:modelValue=“countModel”
@update:modelValue=“$event => (countModel= $event)”
/>

2.2 多个v-model

Vue 3 允许在一个组件上使用多个 v-model

<!-- CustomForm.vue -->
<script setup>
defineProps(['firstName', 'lastName'])
defineEmits(['update:firstName', 'update:lastName'])
</script>

<template>
  <input 
    :value="firstName"
    @input="$emit('update:firstName', $event.target.value)"
  />
  <input 
    :value="lastName"
    @input="$emit('update:lastName', $event.target.value)"
  />
</template>



//父组件
<script setup>
import CustomForm from './components/CustomForm.vue';
import { ref } from 'vue';
const firstName = ref('')
const lastName = ref('')
</script>
<template>
  <div class="container">
    <CustomForm
    v-model:firstName="firstName"
    v-model:lastName="lastName"
  />
  <p>全名:{{ firstName }} {{ lastName }}</p>
  </div>
</template>

2.3 defineModel()

从 Vue 3.4 开始,推荐的实现方式是使用 defineModel() 宏:

<!-- Child.vue -->
<script setup>
const model = defineModel()

function update() {
  model.value++
}
</script>

<template>
  <div>
    <div>Parent bound v-model is: {{ model }}</div>
    <input type="text" v-model="model">
    <button @click="update">Increment</button>
  </div>
</template>

defineModel的写法input绑定值用的是v-model,单个或则多个v-model和底层原理类似的写法

2.4 自定义修饰符

Vue 3 还允许我们为 v-model 创建自定义修饰符。自定义一个capitalize实现首字母大写.

<script setup>
import B from './components/B.vue';
import { ref } from 'vue';
const countModel = ref('');
</script>


<template>
  <div class="container">
    <B v-model.capitalize="countModel"></B>
  </div>
</template>

<template>
<input type="text" :value="modelValue" @input="inputChange">
</template>

<script setup>
import { ref, reactive} from 'vue'
const props = defineProps({
  modelValue:String,
  modelModifiers:{default: ()=> {}}
})
const inputChange =(e) =>{
  let value = e.target.value
  if (props.modelModifiers.capitalize) {
    value = value.charAt(0).toUpperCase() + value.slice(1)
  }
  emit('update:modelValue',value)
}
const emit = defineEmits(['update:modelValue'])
</script>

3.4之后的写法

<!-- Child.vue -->
<script setup>
const [model, modifiers] = defineModel({
  set(val){
    if(modifiers.capitalize){
      return val.charAt(0).toUpperCase() + val.slice(1)
    }
    return val
  }
})
</script>

<template>
  <div>Parent bound v-model is: {{ model }}</div>
  <input type="text" v-model="model">
</template>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值