v-model 是 Vue 提供的一个语法糖,它是 value 值和事件的结合体,它会根据不同的表单项,来选择执行不同的事件。它的作用是,通过和表单元素绑定,实现双向数据绑定,通过表单项可以更改数据。
另外,v-model 还可以用于各种不同类型的输入,、 元素。它会根据所使用的元素自动使用对应的 DOM 属性和事件组合:
和 元素会绑定 value property 并侦听 input 事件; 和 会绑定 checked property 并侦听 change 事件; 会绑定 value property 并侦听 change 事件v-model 会忽略所有表单元素的 value、checked、selected 特性的初始值,而总是将 Vue 实例的数据作为数据来源,应该在 data 选项中声明初始值。
语法糖:这种语法对语言的功能并没有影响,但是更方便程序员使用
在没有使用v-model指令时,我们通过data数据控制表单项中的值,还是麻烦的,需要绑定属性和事件来完成。
<div id="app">
<div>
<input type="text" :value="username" @input="setUsername">
div>
div>
<script>
const vm = new Vue({
el: '#app',
data: {
username: ''
},
methods: {
setUsername(evt) {
this.username = evt.target.value.trim()
}
}
})
script>

使用 v-model 指令实现上述效果:
<div id="app">
<div>
<input type="text" v-model="username">
div>
div>
<script>
const vm = new Vue({
el: '#app',
data: {
username: ''
}
})
script>

使用 v-model 指令,可以很轻松的获取表单中的数据,也可以很轻松地对数据进行修改。
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>vue学习使用title>
<script src="./js/vue.js">script>
head>
<body>
<div id="app">
<div>
<label>
账号:
<input type="text" v-model="username">
label>
div>
<div>
<label>
密码:
<input type="text" v-model="password">
label>
div>
<div>
<textarea v-model="intro">textarea>
div>
<div>
<button @click="dologin">登录系统button>
div>
div>
<script>
const vm = new Vue({
el: '#app',
data: {
username: '',
password: '',
intro: 'hahaha'
},
methods: {
dologin() {
console.log(this.username, this.password, this.intro);
}
}
})
script>
body>
html>

注意:多行文本框中使用插值表达式 无效
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>vue学习使用title>
<script src="./js/vue.js">script>
head>
<body>
<div id="app">
<input placeholder="请输入内容" type="text" v-model="title" @keyup.enter="onEnter">
<hr>
<ul>
<li v-if="todos.length===0">无任务li>
<li v-else v-for="item,index in todos" :key="item.id">
<span>{{item.title}}span>
<span @click="del(index)">删除span>
li>
ul>
div>
<script>
const vm = new Vue({
el: '#app',
data: {
todos: [],
title: ''
},
methods: {
onEnter() {
this.todos.push({
id: Date.now(),
title: this.title
})
this.title = ''
},
del(index) {
// 删除 它可以使用 vue中提供的变异方法splice来完成,用此方法它会触发视图更新
this.todos.splice(index, 1)
}
}
})
script>
body>
html>

当单个复选框被选中或者被取消选中时,我们如何获取到该复选框是否被选中的信息?
我们可以通过绑定事件来获取:
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>vue学习使用title>
<script src="./js/vue.js">script>
head>
<body>
<div id="app">
<div>
<input type="checkbox" @click="clickFn">
<input type="checkbox" @change="clickFn">
div>
div>
<script>
const vm = new Vue({
el: '#app',
data: {
// 单个复选框一定要用布尔类型
checked: false
},
methods: {
clickFn(evt) {
console.log(evt.target.checked);
}
}
})
script>
body>
html>

注意:在绑定事件时,click事件可以用,但它是的状态会太过提前,所以用onchange事件,改变后再来获取。
更简单的方式是,通过 v-model 指令来获取:
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>vue学习使用title>
<script src="./js/vue.js">script>
head>
<body>
<div id="app">
<div>
<input type="checkbox" v-model="checked">
div>
div>
<script>
const vm = new Vue({
el: '#app',
data: {
// 单个复选框一定要用布尔类型
checked: false
},
methods: {
}
})
script>
body>
html>

注意:单个复选框,在数据源中定义的数据类型为布尔类型:true 选中,false未选中
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>vue学习使用title>
<script src="./js/vue.js">script>
head>
<body>
<div id="app">
<div>
<ul>
<li>
<input type="checkbox" value="html" v-model="lessons">html
li>
<li>
<input type="checkbox" value="css" v-model="lessons">css
li>
<li>
<input type="checkbox" value="js" v-model="lessons">js
li>
ul>
<hr>
<div>{{lessons}}div>
div>
div>
<script>
const vm = new Vue({
el: '#app',
data: {
// 默认选中
lessons: ["js",'css']
},
methods: {
}
})
script>
body>
html>

注意:多个复选框,数据源中定义的数据类型为数组,标签中需要指定它的value值。
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>vue学习使用title>
<script src="./js/vue.js">script>
head>
<body>
<div id="app">
<div>
<input type="checkbox" v-model="checked" @change="onSelected">
<hr>
<ul>
<li>
<input type="checkbox" value="html" @change="selectlesson" v-model="lessons">html
li>
<li>
<input type="checkbox" value="css" @change="selectlesson" v-model="lessons">css
li>
<li>
<input type="checkbox" value="js" @change="selectlesson" v-model="lessons">js
li>
ul>
<hr>
<div>{{lessons}}div>
div>
div>
<script>
const vm = new Vue({
el: '#app',
data: {
lessons: [],
checked: false
},
methods: {
onSelected(evt) {
// 选中了
if (evt.target.checked) {
this.lessons = ["js", 'html', 'css']
} else {
this.lessons = []
}
},
selectlesson() {
// 只要来操作数据源就可以改变视图
this.checked = this.lessons.length == 3
}
}
})
script>
body>
html>

DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>vue学习使用title>
<script src="./js/vue.js">script>
head>
<body>
<div id="app">
<div>
<h3>{{sex}} -- {{city}}h3>
<label>
<input type="radio" value="先生" v-model="sex">建行
label>
<label>
<input type="radio" value="女神" v-model="sex">招行
label>
div>
<hr>
<div>
<select v-model="city">
<option value="0">==选择==option>
<option value="wh">芜湖option>
<option value="bj">北京option>
select>
div>
div>
<script>
const vm = new Vue({
el: '#app',
data: {
sex: '先生',
city: '0'
}
})
script>
body>
html>

注意:单选框和复选框都需要 input 标签提供 value 属性。
作用:延时更新数据源中的数据,失去焦点时触发更新。
<div id="app">
<input v-model.lazy="title">
div>
<script>
const vm = new Vue({
el: '#app',
data: {
title: ''
}
})
script>

作用:自动过滤用户输入的首尾空白字符。
<div id="app">
<input v-model.trim="title">
div>
<script>
const vm = new Vue({
el: '#app',
data: {
title: ''
}
})
script>

作用:输入值转为数值类型。
<div id="app">
<input type="number" v-model.number="n1">
+
<input type="number" v-model.number="n2">
= {{n1+n2}}
div>
<script>
const vm = new Vue({
el: '#app',
data: {
n1: 1,
n2: 2
}
})
script>

DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>vue学习使用title>
<script src="./js/vue.js">script>
head>
<body>
<div id="app">
<table border="1" width="600">
<tr>
<th>序号th>
<th>名称th>
<th>单价th>
<th>数量th>
<th>操作th>
tr>
<tr v-for="item,index in carts">
<td>{{index+1}}td>
<td>{{item.name}}td>
<td>{{item.price}}td>
<td>
<button @click="setNum(1,index)">+++button>
<input type="number" v-model="item.num">
<button @click="setNum(-1,index)">---button>
td>
<td>
<button @click="del(index)">删除button>
td>
tr>
table>
<hr>
<h3>
合计:
{{totalPrice()}}
h3>
div>
<script>
const vm = new Vue({
el: '#app',
data: {
carts: [
{ id: 1, name: '小米12pro', price: 1, num: 1 },
{ id: 2, name: '华为手机', price: 2, num: 1 },
{ id: 3, name: '水果手机', price: 3, num: 1 },
]
},
methods: {
setNum(n, index) {
this.carts[index].num += n
if (this.carts[index].num <= 1) this.carts[index].num = 1
if (this.carts[index].num >= 3) this.carts[index].num = 3
// 用最大值和最小值来限制它的范围,可以了解一下这种写法
// this.carts[index].num = Math.min(3, Math.max(1, this.carts[index].num))
},
totalPrice() {
// 聚合运算
return this.carts.reduce((prev, { price, num }) => {
prev += price * num
return prev
}, 0)
},
del(index) {
// 弹出确认框
confirm('确定删除') && this.carts.splice(index, 1)
}
}
})
script>
body>
html>

DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>vue学习使用title>
<script src="./js/vue.js">script>
head>
<body>
<div id="app">
<table border="1" width="600">
<tr>
<th>序号th>
<th>名称th>
<th>单价th>
<th>数量th>
<th>操作th>
tr>
<tr v-for="item,index in carts">
<td>{{index+1}}td>
<td>{{item.name}}td>
<td>{{item.price}}td>
<td>
<button @click="setNum(1,index)">+++button>
<input type="number" v-model="item.num">
<button @click="setNum(-1,index)">---button>
td>
<td>
<button @click="del(index)">删除button>
td>
tr>
table>
<hr>
<h3>
合计:
{{totalPrice()}}
h3>
div>
<script>
// 初始数据应该从本地存储中读取
function getCarts() {
return !window.localStorage.getItem('carts') ? [{ id: 1, name: '小米12pro', price: 1, num: 1 },
{ id: 2, name: '华为手机', price: 2, num: 1 },
{ id: 3, name: '水果手机', price: 3, num: 1 }] : JSON.parse(window.localStorage.getItem('carts'))
}
function setCarts(carts) {
window.localStorage.setItem('carts', JSON.stringify(carts))
}
const vm = new Vue({
el: '#app',
data: {
carts: getCarts()
},
methods: {
setNum(n, index) {
this.carts[index].num += n
if (this.carts[index].num <= 1) this.carts[index].num = 1
if (this.carts[index].num >= 3) this.carts[index].num = 3
// 用最大值和最小值来限制它的范围,可以了解一下
// this.carts[index].num = Math.min(3, Math.max(1, this.carts[index].num))
setCarts(this.carts)
},
totalPrice() {
return this.carts.reduce((prev, { price, num }) => {
prev += price * num
return prev
}, 0)
},
del(index) {
if(confirm('确定删除')){
this.carts.splice(index, 1)
setCarts(this.carts)
}
}
}
})
script>
body>
html>
