v-on
1. 介绍
- 作用:绑定事件监听器
- 缩写:@
- 预期:Function | Inline Statement | Object
- 参数: event
2. 参数传递
- 如果该方法不需要额外参数,那么方法后的 () 可以不添加。
注
如果方法本身有一个或多个参数,那么会默认将原生事件 event 参数传递给第一个参数 - 如果需要同时传入某个参数,同时需要 event 时,可以通过 $event 传入事件
3. 修饰符
.stop
:调用event.stopPropagation()
,阻止冒泡.prevent
:调用event.preventDefault()
,阻止默认行为.[keyCode | keyAlias]
:只有当事件从特定键触发时才触发回调.native
:监听组件根元素的原生事件.once
:只触发一次回调
<!--1. .stop的使用,btn的click事件不会传播,不会冒泡到上层,调用event.stopPropagation() -->
<div @click="divClick">
<button @click.stop="btnClick">按钮1</button>
</div>
<!-- 2. .prevent 调用event.preeventDefault阻止默认行为 -->
<form action="www.baidu.com">
<button type="submit" @click.prevent="submitClick">提交</button>
</form>
<!--3. 监听键盘的事件 -->
<input type="text" @click.enter="keyup">
v-if、v-else、v-if-else
- v-if 的条件为 false 时,对应的元素以及其子元素不会渲染,也就是不会有对应的标签出现在 DOM 中
1. 切换小案例
<div id="app">
<span v-if="isPhone">
<label for="phone">用户电话:</label>
<input type="text" id="phone" placeholder="请输入电话号">
</span>
<span v-else>
<label for="email">用户邮箱:</label>
<input type="text" id="email" placeholder="请输入邮件" >
</span>
<button @click="btnClick()">切换类型</button>
</div>
问题 切换后,输入框中的内容没有消失
解决方法 key
- key 是各不相同的
<div id="app">
<span v-if="isPhone">
<label for="phone">用户电话:</label>
<input type="text" id="phone" placeholder="请输入电话号" key="phone">
</span>
<span v-else>
<label for="email">用户邮箱:</label>
<input type="text" id="email" placeholder="请输入邮件" key="email">
</span>
<button @click="btnClick()">切换类型</button>
</div>
2. v-show 和 v-if 的区别
- v-if 条件为 false 时,不会有对应的元素存在于 DOM 中
- v-show 条件为 false 时,仅仅是将元素的 display 属性置为 none
- 选择:
- 当需要在显示与隐藏之间频繁切换时,使用 v-show
- 当只有一次切换时,使用 v-if
v-for 遍历数组和对象
1. 遍历数组
<div id="app">
<!-- 1.遍历过程没有使用索引(下标值) -->
<ul>
<li v-for="item in names" >{{item}}</li>
</ul>
<!-- 2.遍历过程有使用索引(下标值) -->
<ul>
<li v-for="(item,index) in names" >{{index+":"+item}}</li>
</ul>
</div>
2. 遍历对象
<div id="app">
<!-- 1. 遍历 value -->
<ul>
<li v-for="value in user" >{{value}}</li>
</ul>
<!-- 2. value-key -->
<ul>
<li v-for="(value,key) in user" >{{key+"-"+value}}</li>
</ul>
<!-- 3. value-key-index -->
<ul>
<li v-for="(value,key,index) in user" >{{key+"-"+value+"-"+index}}</li>
</ul>
</div>
3. key 属性
官方推荐:使用 v-for 时,给对应的元素或组件加上一个 :key 属性
- key 的作用主要是为了高效的更新虚拟 DOM
- 不加key渲染时候会依次替换渲染,加了key会直接将其放在指定位置,加key提升效率
<body>
<div id="app">
<!-- 不加key如果要插入f,要依次改变插入位置之后的所有元素 -->
<ul>
<li v-for="item in letters">{{item}}</li>
</ul>
<button @click="add1">没有key</button>
<!-- 加key,如果要插入f,使用diff算法高效,index会一直变,所以item如果唯一可以使用item-->
<ul>
<li v-for="item in letters" :key="item">{{item}}</li>
</ul>
<button @click="add2">有key</button>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js"></script>
<script>
const app = new Vue({
el:"#app",
data:{
letters:['a','b','c','d','e']
},
methods: {
add1(){
this.letters.splice(2,0,'f')
},
add2(){
this.letters.splice(2,0,'f')
}
}
})
</script>
</body>
4. 数组的响应式方法
<body>
<div id="app">
<ul>
<li v-for="item in letters">{{item}}</li>
</ul>
<button @click="btn1">push</button><br>
<button @click="btn2">通过索引值修改数组</button>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js"></script>
<script>
const app = new Vue({
el:"#app",
data:{
letters:['a','b','c','d','e']
},
methods: {
btn1(){
//1.push
this.letters.push('f');
//2.pop()删除最后一个元素
//this.letters.pop();
//3.shift()删除第一个
//this.letters.shift();
//4.unshift()添加在最前面,可以添加多个
//this.letters.unshift('aaa','bbb','ccc');
//5.splice():删除元素/插入元素/替换元素
// this.letters.splice(2,0,'aaa');
//6.sort()排序可以传入一个函数
//this.letters.sort();
//7.reverse()反转
// this.letters.reverse();
},
btn2(){
this.letters[0]='f';
}
}
})
</script>
</body>
-
通过索引值修改数组的值,这种情况不是响应式的
-
通过数组的方法,例如
push()
、pop()
、shift()
、unshift()
、splice()
、sort()
、reverse()
等方法修改数组的数据,DOM元素会随之修改 -
splic()
:删除元素、插入元素、替换元素splice(1,1)
:在索引为1的地方删除一个元素,第二个元素不传,直接删除后面所有元素
splice(index,0,'aaa')
:在索引 index 后面删除0个元素,加上’aaa’
splice(1,1,'aaa')
:替换索引为 1 的后一个元素为’aaa’
购物车小demo
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Day01</title>
<style>
#shopping-cart {
margin: 100px;
}
table {
width: 600px;
border: 1px;
border-collapse: collapse;
border-spacing: 0;
box-shadow: 3px 3px 10px #aaaaaa;
}
th,
td {
padding: 8px 16px;
border: 1px solid #e9e9e9;
text-align: left;
}
th {
background-color: #f7f7f7;
color: #5c6b77;
font-weight: 600;
}
</style>
</head>
<body>
<div id="shopping-cart">
<table>
<thead>
<tr>
<th>书籍名称</th>
<th>出版日期</th>
<th>价格</th>
<th>购买数量</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<tr v-for="(item,index) in books" :key="index">
<td>{{item.name}}</td>
<td>{{item.beginDate}}</td>
<td>{{item.price | formatPrice}}</td>
<td><button @click="decrease(index)" :disabled="item.count<=0">-</button>{{item.count}}<button @click="increase(index)">+</button></td>
<td><button @click="remove(index)">移除</button></td>
</tr>
</tbody>
</table>
<h3>总价格为:{{sum | formatPrice}}</h3>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js"></script>
<script>
const app = new Vue({
el: "#shopping-cart",
data: {
books: [{
name: "《算法导论》",
beginDate: "2006-9",
price: 85.00,
count: 1
},
{
name: "《UNIX编程艺术》",
beginDate: "2006-2",
price: 59.00,
count: 1
},
{
name: "《编程大全》",
beginDate: "2008-10",
price: 39.00,
count: 1
},
{
name: "《代码大全》",
beginDate: "2006-3",
price: 128.00,
count: 1
}],
},
methods: {
increase(index) {
return this.books[index].count++;
},
decrease(index) {
return this.books[index].count > 0 ? this.books[index].count-- : false;
},
remove(index) {
return this.books.splice(index, 1);
},
},
computed: {
sum() {
let totalPrice = 0;
// 1. 普通for循环
// for (let i = 0; i < this.books.length; i++) {
// totalPrice += this.books[i].price * this.books[i].count;
// }
// 2.增强for循环
// for (let i in this.books) {
// totalPrice = totalPrice + this.books[i].price * this.books[i].count;
// }
// 3.for of
// for (const book of this.books) {
// totalPrice = totalPrice + book.price * book.count;
// }
// return totalPrice;
// 4. 使用高阶函数
// return this.books.map(function (book) {
// return book.price * book.count;
// }).reduce(function (preValue,currentValue) {
// return preValue + currentValue;
// })
// 5. 高阶函数简写(箭头函数)
return this.books.length === 0 ? 0 : this.books.map(book => book.price * book.count).reduce((preValue,currentVlue) => preValue + currentVlue);
}
}
},
filters: { //过滤器
formatPrice(price) {
return "¥" + price.toFixed(2);
}
}
})
</script>
</body>
</html>
3. 函数解析
- filter过滤函数
const nums = [2,3,5,1,77,55,100,200];
// 要求: 获取nums中大于50的数
// 回调函数会遍历nums中每一个数,传入回调函数,在回调函数中写判断逻辑,返回true则会被数组接收,false会被拒绝
let newNums = nums.filter(function (num) {
if(num > 50){
return true;
}
return false;
})
// 可以使用箭头函数简写
// let newNums = nums.filter(num => num >50)
- map 高阶函数
// 要求: 将已经过滤的新数组每项乘以2
// map函数同样会遍历数组每一项,传入回调函数为参数,num是map遍历的每一项,回调函数function返回值会被添加到新数组中
let newNums2 = newNums.map(function (num) {
return num * 2;
})
// 简写
// let newNums2 = newNums.map(num => num * 2)
- reduce 高阶函数
// 要求: 将newNums2的数组所有数累加
// reduce函数同样会遍历数组每一项,传入回调函数和‘0’为参数,0表示回调函数中preValue初始值为0,回调函数中参数preValue是每一次回调函数function返回的值,currentValue是当前值
// 例如数组为[154, 110, 200, 400],则回调函数第一次返回值为0+154=154,第二次preValue为154,返回值为154+110=264,以此类推直到遍历完成
let newNum = newNums2.reduce(function (preValue,currentValue) {
return preValue + currentValue;
},0)
//简写
// let newNum = newNums2.reduce((preValue,currentValue) => preValue + currentValue)
// 三个需求综合
let n = nums.filter(num => num > 50).map(num => num * 2).reduce((preValue,currentValue) => preValue + currentValue);
v-model
- 实现表单元素和数据的双向绑定
1. 绑定 input
<input type="text" v-model="message">
<h2>{{message}}</h2>
2. v-bind 和 v-on 实现 v-model
<input type="text" :value="message2" @input="message2 = $event.target.value">
<h2>{{message2}}</h2>
3. v-model 结合 radio
- radio单选框的
name
属性是互斥的,如果使用 v-model,可以不使用name
就可以互斥
<div id="app">
<label for="male">
<input type="radio" id="male" name="sex" value="男" v-model="sex">男
</label>
<label for="female">
<input type="radio" id="female" name="sex" value="女" v-model="sex">女
</label>
<div>你选择的性别是:{{sex}}</div>
</div>
4. v-model 结合 checkbox
- 单选框
<label for="agree">
<input type="checkbox" id="agree" v-model="isAgree">同意协议
</label>
<h2>isAgree:{{isAgree}}</h2>
<button :disabled="!isAgree">下一步</button>
- 复选框
<input type="checkbox" value="A" v-model="letter">A
<input type="checkbox" value="B" v-model="letter">B
<input type="checkbox" value="C" v-model="letter">C
<input type="checkbox" value="D" v-model="letter">D
<input type="checkbox" value="E" v-model="letter">E
<h2>{{letter}}</h2>
5. v-model 结合 select
<select name="" id="fruit" v-model="fruit">
<option value="apple">apple</option>
<option value="banana">banana</option>
<option value="orange">orange</option>
<option value="grape">grape</option>
<option value="peach">peach</option>
</select>
<h2>fruit:{{fruit}}</h2>
<select name="" id="fruits" v-model="fruits" multiple>
<option value="apple">apple</option>
<option value="banana">banana</option>
<option value="orange">orange</option>
<option value="grape">grape</option>
<option value="peach">peach</option>
</select>
<h2>fruits:{{fruits}}</h2>
6. 值绑定
- 动态给 value 赋值
<label :for="item" v-for="item in sports">
<input type="checkbox" :value="item" :id="item" v-model="selectedSports">{{item}}
</label>
<h4>selectedSports:{{selectedSports}}</h4>
const app = new Vue({
el: "#app",
data: {
selectedSports: [],
sports: ['篮球', '台球', '足球', '羽毛球', '高尔夫球', '排球', '跳高', '跳远', '自行车', '滑冰', '滑雪'],
}
})
7. 修饰符
.lazy
:让数据在失去焦点或者回车时才会更新.number
:v-model 默认情况下,输入框中的内容都是字符串类型,.number
修饰符可以让输入框中输入的内容自动转换为数字类型.trim
:过滤内容两端的空格