每天对自己多问几个为什么,总是有着想象不到的收获。 一个菜鸟小白的成长之路(copyer)
v-model的使用场景分为两种,一种在表单
中,一种在组件
中
表单中使用
v-model的使用原理: 利用v-bind动态绑定value值,v-on监听触发的input事件,来修改value值
<template id="james">
// v-bind: value 拿到data中的初始数据
// v-on:input 监听changeMessage事件
<input type="text" :value="message" @input="changeMessage">
<div>{{message}}</div>
</template>
<script>
Vue.createApp({
template: "#james",
data() {
return {
message: 'james'
}
},
methods: {
changeMessage(e) { //拿到input的value值,修改message
this.message = e.target.value
}
}
}).mount("#app")
</script>
表单中的使用场景:
1、input输入框
<template>
<input v-model="message" />
</template>
<script>
data() {
return {
message: 'james'
}
}
</script>
2、复选框
单选框
<template>
<label for="agree">
//当value为true的时候,复选框就被选中了
<input type="checkbox" id="agree" v-model="agree">同意协议
</label>
</template>
<script>
data() {
return {
agree: false
}
}
</script>
多选框
<template>
<label for="james">
<input type="checkbox" id="james" v-model="people" value="james">james
</label>
<label for="kobe">
<input type="checkbox" id="kobe" v-model="people" value="kobe">kobe
</label>
<label for="curry">
<input type="checkbox" id="curry" v-model="people" value="curry">curry
</label>
<div>{{people}}</div>
</template>
<script>
data() {
return {
people: []
}
},
</script>
多选框: 一定要注意, 每个input必须要要对应一个value值,不然v-model不知道把什么数据添加在数组里面
3、单选框
<template>
<label for="male">
<input type="radio" v-model="gender" value="male" id="male">男
</label>
<label for="female">
<input type="radio" v-model="gender" value="female" id="female">女
</label>
<div>{{gender}}</div>
</template>
<script>
data() {
return {
gender: 'male'
}
},
</script>
注意: type 为radio, v-model绑定同一值,那么他们就是互斥的
4、选择框
<select v-model="lover"> //想要多选: multiple
<option value="james">james</option>
<option value="curry">curry</option>
<option value="kobe">kobe</option>
</select>
<div>{{lover}}</div>
<script>
data() {
return {
lover: 'james'
}
},
</script>
5、修饰符
//懒加载
<input type="text" v-model.lazy="agree">
//绑定类型
<input type="text" v-model.number="agree">
//去掉空格
<input type="text" v-model.trim="agree">
组件中使用
组件之间进行双向绑定,也可以使用v-model
比如:下面自定义了一个my-input
的组件, 把父组件中的message传递给子组件
<my-input v-model="message"></my-input>
//等价于
<my-input :modelValue="message" @update:model-value="message = $event">
</my-input>
//modelValue 默认绑定的值,需要在子组件中props注册
//@update:model-value监听model-value事件的更新,然后把$event赋值给message
//这里因为是组件,所以是$event,这是组件中$emit,传递过来的参数,而不是$event.target.value
实例代码:
//App.vue
<template>
<div>
<my-input v-model="message"></my-input>
</div>
</template>
<script lang="ts">
import { defineComponent } from 'vue'
import MyInput from './MyInput.vue'
export default defineComponent({
data() {
return {
message: 'kobe'
}
},
components: {
MyInput
}
})
</script>
上面的代码中,我们注册了一个子组件my-input
,然后通过 v-model
把父组件中的message传递给子组件
//MyInput.vue
<template>
<div>
<input :value="modelValue" @input="inputEvent"/>
<h2>{{modelValue}}</h2>
</div>
</template>
<script lang="ts">
import { defineComponent } from 'vue'
export default defineComponent({
props: { //v-model传递下来的默认modelValue
modelValue: String
},
//注册emit事件 (可以使用驼峰命名)
emits: ['update:modelValue'],
methods: {
inputEvent(e: any) {
//$emit传递给父组件方法,和输入的input值
this.$emit('update:modelValue', e.target.value)
}
}
})
</script>
在子组件my-input
内部有个input输入框,动态绑定传递下来的 props, 然后监听input
事件,通过emit
事件来触发update:modelValue
,把修改的值传递给父元素,通知父元素修改。
在上面的子组件中的
<input :value="modelValue" @input="inputEvent"/>
//这不就相当于表单中的v-model嘛,那么我们可以直接使用v-model吗
<input v-model="modelValue" />
//很显然是不行的
//原因: 子组件直接修改了props的值,这违背了数据的单向流
//就算修改了,但是没有触发@update:model-value这个函数,父组件就不会更新
那如果,就是想在子组件中使用v-model
,那么该怎么处理呢?
这样就需要重新定义变量,来保存props传递过来的,这里建议是computed
计算属性
<input v-model="modelValue" />
props: { //v-model传递下来的默认modelValue
modelValue: String
},
computed: {
value: {
get() {
return this.modelValue //getter函数直接返回modelvalue属性值
},
//使用setter方法,当值修改的时候,就触发update这个函数
set(value) {
this.$emit('update:modelValue', value)
}
}
}
完成目标
在组件中使用多个v-model
<MyInput v-model:message="message" v-model:title="title" />
//message 和 title就是新的名字, 去掉modelValue
//MyInput.vue
props: {
message: String,
title: String
}
emits:['update:message', 'update:title']
//然后接下来的逻辑跟上面一样