1.v-if和v-show的使用与区别
1.1 v-if
v-if用来控制是否显示包含该元素的块是否显示。接收一个布尔类型的值,为true的时候则显示,为false的时候就不显示。通常与v-else或者v-elseif配合使用。类似于代码中的if-else判断和if-elseif-else判断的使用。
<div v-if="isshow">
<p>这是if判断中的文本</p>
</div>
<div v-else>
<p>这是else判断中的文本</p>
</div>
如果不显示,在DOM结构中,vue会将该元素直接注释掉。在查看Elements结构的时候。将会看到有一行的内容为注释行“<!---->”
1.2 v-show
与v-if相同,都是控制使用的元素是否显示。同样也是接收一个布尔类型的值。与v-if不同,当为false的时候,vue只是将其display设置为了none值。并没有完全将其从DOM中移除。
1.3 两者的使用地方
v-if适合于那种决定性的显示。类似于某些权限下使用到某些功能模块,这个时候就适合使用v-if来控制是否显示。
v-show适合控制那些需要来回显示的内容。
1.4 衍生出的知识点
vue内部的虚拟DOM有一个复用。在切换显示内容的时候。如果两个的DOM结构一样,则vue的虚拟DOM则会优先复用。即替换其中某些值得参数,列如id、value等。这会导致,用户在界面A的input中输入的内容,在界面B输入的时候依然存在。如果希望vue的虚拟DOM不复用input,需要为两个界面的input添加一个key。使用不同的两个v-bind:key的值来标记,这样虚拟DOM就不会去复用有key标记过的元素。
2.v-for的循环遍历
2.1 v-for的基本使用
v-for用于遍历数组,也适合与对象数组。可以适用于需要输出同样的元素结构,但内容不同的界面。例如table中的列,ul或者ol列表中的内容,甚至是个性化定制的div元素界面。
假如我们有这样的一个数组,里面存储了一些水果的名字。那么,可以通过下面的方式使用ul来将其显示。因为我们需要显示多个li,所以我们需要在li元素中加入v-for。
<div id="shuiguo">
<ul>
<li v-for="item in fruits">{{item}}</li>
</ul>
</div>
<script>
const app = new Vue({
el:'#shuiguo',
data:{
fruits:['苹果','香蕉','葡萄','芒果']
}
})
</script>
当我们需要同时显示出,这个数组的下标时,我们就不能只使用item了,需要使用括号。第一个参数依然是我们遍历出来的对象或内容,第二个值为下标。
<div id="shuiguo">
<ul>
<li v-for="(item,index) in fruits">{{index}}--{{item}}</li>
</ul>
</div>
<script>
const app = new Vue({
el:'#shuiguo',
data:{
fruits:['苹果','香蕉','葡萄','芒果']
}
})
</script>
2.2 v-for的遍历对象数组
有时候数组可能是对象,此时代表的item就是对象,要像使用对象一样来使用item
<div id="man">
<div v-for="people in body">
<h2>这是名字:{{people.name}}</h2>
<p>这是年龄:{{people.age}}</p>
</div>
</div>
<script>
const app = new Vue({
el:'#man',
data:{
body:[
{name:'张三',age:18},
{name:'李四',age:20},
{name:'王五',age:23}
]
}
})
</script>
2.3 为v-for遍历的内容增加key
数组的内容可能会增加,如果没有为遍历的内容添加v-bind:key,虚拟DOM进行元素添加的时候会不太智能。此时衍生出了虚拟DOM的Diff算法。因此,可以为每一个遍历的内容添加一个不会重复的key。一般为遍历出来的item内容。
2.4 哪些操作数组的方法可以让vue刷新界面
数组的内容除了添加还有删除以及修改。某些对数组的操作会让vue进行响应,因为vue是响应式的。
- 数组的push方法,该方法向数组最后添加一个数组内容
- 数组的pop方法,该方法将删除数组最后一个内容
- 数组的shift方法,该方法将删除数组的第一个内容
- 数组的unshift(item),该方法将item添加到数组的头部
- 数组的sort方法,该方法可以将数组进行排序
- 数组的reverse方法,该方法将数组内容进行翻转,从尾部排列到头部
- 数组的splice方法,该方法可以插入、修改或者删除数组内容
直接通过数组的下标来修改对应的内容,vue将不会刷新界面。可以使用splice来修改,或者使用vue自带的Vue.set(要修改的对象,索引值,替换的值)来修改。
3.一个案例,结合之前学过的vue知识点
书籍购物车,通过table表格来模拟一个购物车。统合了前期学习的vue知识点,模拟购物功能(增加数量/减少数量)/(按钮的点击功能),移除功能(数组的操作),当购物车为空时显示另外的界面(v-if、v-show的使用),以及统计总价格(computed知识点的使用)
<!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">
<script src="../js/vue.js"></script>
<title>Document</title>
<style>
table {
border: 1px solid #e9e9e9;
border-collapse: collapse;
border-spacing: 0;
}
th,
td {
padding: 9px 16px;
border: 1px solid #e9e9e9;
text-align: left;
}
th {
background-color: #f7f7f7;
color: #5c6b77;
font-weight: 600;
}
table tr:nth-child(odd) {
background-color: gray;
}
.app h2 {
color: red;
}
</style>
</head>
<body>
<div id="app">
<div v-if="books.length">
<table>
<thead>
<th>索引</th>
<th>书籍名称</th>
<th>出版日期</th>
<th>价格</th>
<th>购买数量</th>
<th>操作</th>
</thead>
<tr v-for="(book,index) in books">
<td>{{index+1}}</td>
<td>{{book.name}}</td>
<td>{{book.date}}</td>
<td>{{book.price | showPrice}}元</td>
<td>
<button @click="itemLessNumber(index)" v-bind:disabled="book.number===1">-</button><span>{{book.number}}</span><button @click="itemAddNumber(index)">+</button>
</td>
<td>
<button @click="removeBook(index)">移除</button>
</td>
</tr>
</table>
<span>总价格:{{Allprice | showPrice}} 元</span>
</div>
<h2 v-else>购物车为空</h2>
</div>
<script>
const app = new Vue({
el: '#app',
data: {
books: [{
name: '语文',
price: 25,
date: '1997-11-04',
number: 1
}, {
name: '数学',
price: 24,
date: '1997-11-04',
number: 1
}, {
name: '英语',
price: 22,
date: '1997-11-04',
number: 1
}, {
name: '政治',
price: 30,
date: '1997-11-04',
number: 1
}, {
name: '地理',
price: 21,
date: '1997-11-04',
number: 1
}, {
name: '历史',
price: 20,
date: '1997-11-04',
number: 1
}]
},
computed: {
Allprice: {
get: function() {
var number = 0;
for (let index = 0; index < this.books.length; index++) {
const element = this.books[index];
number += (element.number * element.price);
}
return number;
}
}
},
methods: {
itemAddNumber(index) {
this.books[index].number++;
},
itemLessNumber(index) {
this.books[index].number--;
if (this.books[index].number < 1) {
this.books[index].number = 1;
}
},
removeBook(index) {
this.books.splice(index, 1)
}
},
filters: {
showPrice(price) {
return price.toFixed(2)
}
}
})
</script>
</body>
</html>
4.由一个案例所引出的知识点:函数式编程/链式编程
4.1 方法会改变调用对象的内容还是生成新的对象
4.1.1 Object调用的方法会改变自身
以数组为例子,一个数组调用了sort()方法进行了排序。此时不需要新建一个新的变量来接收返回值。sort()方法直接改变了数组的排序。
4.1.2 Object调用的方法不会改变自身
以字符串对象为例子,当使用substring()方法对字符串进行截取的时候,需要定义一个变量来接收新的字符串,此时原先的字符串不会有任何的改变。
4.2 链式编程,就是一连串的方法调用
数组调用方法之后会返回数组,字符串调用方法之后会返回字符串,如果需要对一个变量进行多个方法的调用。比如将一串文字,进行内容翻转。我们需要使用到split()方法对字符串进行分割,再使用reverse()方法进行翻转,再使用join()将其拼接。
我们不需要在每一步都定义一个新的变量来保存结果,我们可以直接使用一行代码。
var newString = "你好啊,陌生人".split('').reverse().join('')
当我们使用log打印之后,就是显示这段文字翻转后的内容了。
4.2 高阶函数
现在有一个场景,有一个数组,里面存储了一些数值,没有按大小顺序来排列。现在有一个需求,需要你筛选出其中大于50的值,将这些值乘以2,再求和。
我们需要使用三个变量来存储,第一个变量A用来存储筛选大小后的数组,第二个变量B在变量A的基础上将值都乘以2,第三个变量C在变量B的基础将这些值相加求和。
如果我们使用高阶函数,可以不用定义如此多的变量来完成这个需求。
使用filter()高阶函数来进行特定的筛选,使用map函数来对数组的值进行操作,使用reduce()函数来进行求值。这时候,我们就可以有更容易阅读的方法来实现这个需求,当然,需要知道这三个函数的时候方法为前提。
// filter函数
const num = ['10', '20', '111', '222', '30', '40'];
const newnum1 = num.filter(function(n) {
return n < 100;
})
console.log(newnum1);
// map函数
const newnum2 = newnum1.map(function(n) {
return n * 2;
})
console.log(newnum2);
// reduce函数
const newnum3 = newnum2.reduce(function(previousValue, currentValue, currentIndex) {
console.log('当前操作的下标' + currentIndex, '之前的previousValue的值为:' + previousValue);
return previousValue + currentValue;
}, 0)
console.log(newnum3);
const result = num.filter(function(n) {
return n < 100
}).map(function(n) {
return n * 2
}).reduce(function(previousValue, currentValue) {
return previousValue + currentValue;
}, 0);
console.log(result);
5.v-model的使用
5.1 v-model的基本使用和一些控件的交互
在元素中使用v-model来定义数据的双向交互。定义的内容改变会体现在界面上,同时用户更改界面的时候也会改变其内容。
例如使用v-model为一个input输入框对一个message变量进行双向绑定,用户输入的时候可以改变message的值。代码改变message的值时也会体现在输入框中。
5.2 v-model的原理
可以使用v-bind:value对输入框的值进行绑定,这样message的内容也是可以显示在内容中。监听输入事件,当输入框中的内容改变时,更改message的值。这样也相当于实现了双向绑定。
5.3 v-model与其他控件的交互
5.3.1与radio单项选择的交互
每当选中不同的单项内容时,对应绑定的sex都会改变。
<div id="app">
<label for="male">
<input type="radio" id="male" v-model="sex" value="男">男
</label>
<label for="female">
<input type="radio" id="female" v-model="sex" value="女">女
</label>
<h2>您选择的性别是:{{sex}}</h2>
<h2>{{message}}</h2>
</div>
<script>
const app = new Vue({
el: '#app',
data: {
message: '你好啊',
sex: '男'
}
})
</script>
5.3.2与checkbox多选框的交互
checkbox的勾选框需要考虑单个与多个的情况,两个情况都不同
<div id="app">
<!-- 单选框情况 -->
<label for="agree">
<input type="checkbox" id="agree" v-model="isAgree">同意协议
</label>
<br>
<h2>是否勾选中:{{isAgree}}</h2>
<button v-bind:disabled="!isAgree">下一步</button>
<br>
<!-- 多选框情况 -->
<label for="baskteboll"><input type="checkbox" value="篮球" id="baskteboll" v-model="hobbies">篮球</label>
<label for="vollyboll"><input type="checkbox" value="排球" id="vollyboll" v-model="hobbies">排球</label>
<label for="pinpanboll"><input type="checkbox" value="乒乓球" id="pinpanboll" v-model="hobbies">乒乓球</label>
<label for="brathboll"><input type="checkbox" value="羽毛球" id="brathboll" v-model="hobbies">羽毛球</label>
<label for="tabelboll"><input type="checkbox" value="网球" id="tabelboll" v-model="hobbies">网球</label>
<br>
<h2>您选择的爱好是:{{hobbies}}</h2>
<!-- 关于值绑定 -->
<label v-for="item in originHobbies" v-bind:for="item">
<input type="checkbox" v-bind:id="item" v-bind:value="item" v-model="newhobbies">{{item}}
</label>
<h2>您选择的爱好是:{{newhobbies}}</h2>
</div>
<script>
const app = new Vue({
el: '#app',
data: {
message: '你好啊',
isAgree: false,
hobbies: [],
originHobbies: ['篮球', '羽毛球', '排球', '乒乓球', '网球', '桌球'],
newhobbies: []
}
})
</script>
5.3.3与select的交互
同样也需要考虑单选与多选的情况
<div id="app">
<!-- 单选的情况 -->
<select name="abc" v-model="fruit">
<option value="苹果">苹果</option>
<option value="芒果">芒果</option>
<option value="香蕉">香蕉</option>
<option value="葡萄">葡萄</option>
<option value="榴莲">榴莲</option>
</select>
<h2>您选择的是:{{fruit}}</h2>
<br>
<select name="bcd" v-model="fruits" multiple>
<option value="苹果">苹果</option>
<option value="芒果">芒果</option>
<option value="香蕉">香蕉</option>
<option value="葡萄">葡萄</option>
<option value="榴莲">榴莲</option>
</select>
<h2>您选择的是:{{fruits}}</h2>
</div>
<script>
const app = new Vue({
el: '#app',
data: {
fruit: '香蕉',
fruits: []
}
})
</script>
5.3.4 v-model的修饰符的使用
修饰符用来处理一些特殊的情况,例如v-model.lazy修饰符的作用是延时同步。在输入框失去焦点或者使用回车键时,才会同步去更新v-model绑定的内容。
number修饰符可以确保用户输入的内容会被转为数值类型,可以很好的处理一些计算。如果没有使用该修饰符,则v-model绑定的内容会是string类型。
trim修饰符就像字符串中的trim一样,可以去除输入框中开头和结尾输入的空格。
6.vue的组件化开发
6.1vue的组件化思想和使用
组件化的思想,可以让一些经常使用得到,或者多个页面有同样样式的内容可以进行复用。将每一块每一个控件都视作组件。可以自定义控件名称,在挂载了vue的控件上直接使用。
vue自定义组件有三步,第一步:定义组件的构造,样式以及内容。第二步:声明控件的名称,以及所对应的组件构造器。第三步:在挂载了vue的控件中使用。
6.2vue的全局组件以及局部组件
没有在声明的vue中声明使用的组件为全局组件,类似于全局作用域和局部作用域。如果在一个挂载的vue中进行声明,那么该自定义控件只能在挂载了该vue的控件内使用。
6.3父组件和子组件
包含关系,在组件中可以包含组件。包含组件的叫父组件,被包含的叫子组件。
6.3.1 父组件与子组件的数据通信
当在父组件中定义了一个数据message,此时需要将该数据传给子组件。在子组件中使用props声明自己使用的数据,在子组件的template的html模板中使用该数据。在父组件中,通过v-bind的方式绑定子组件声明的props属性。
<div id="app">
<cpn v-bind:cmovies="movies"></cpn>
</div>
<template id="cpn">
<div>
<p>这是数组movies:{{cmovies}}</p>
<p>这是消息message:{{cmessage}}</p>
</div>
</template>
<script>
// 父传子
const cpn = {
template: '#cpn',
// 数组方式
// props: ['cmovies', 'cmessage'],
// 对象形式
props: {
// 1.限制类型
// cmovies: Array,
// cmessage: String
// 2.设置默认值
// 当属性类型是对象或者数组时,默认值必须是函数的返回值
cmovies: {
type: Array,
default () {
return []
}
},
cmessage: {
type: String,
default: '这是消息的默认值',
// required: true 控制该属性是否必须传递
}
},
data() {
return {
}
},
methods: {
}
}
const app = new Vue({
el: '#app',
data: {
message: '你好啊',
movies: ['海王', '海贼王', '海尔兄弟']
},
components: {
cpn
}
})
</script>
props的设置,可以限制传输的类型以及默认值。设置了默认值之后,如果没有赋值,那么它将使用默认值。
除了父组件可以传值给子组件,子组件也可以通过方法的方式,向父组件传递信息。
6.3.2 子组件传给父组件
一个子组件中有一个按钮,点击该按钮后,向父组件传递一些信息。此时需要使用$emit来发送信息。$emit可以接受两个参数,至少要有一个参数。第一个参数为事件名称,第二个为参数。$emit第一个参数的事件名称,需要父组件在使用的时候去监听处理,类似于点击事件等。
<div id="app">
<cpn v-on:item-click="cpnClick"></cpn>
</div>
<template id="cpn">
<div>
<button v-for="item in categories" @click="btnclick(item)">{{item.name}}</button>
</div>
</template>
<script>
const cpn = {
template: '#cpn',
data() {
return {
categories: [{
id: 'aaa',
name: '热门推荐'
}, {
id: 'bbb',
name: '手机数码'
}, {
id: 'ccc',
name: '家用家电'
}, {
id: 'ddd',
name: '电脑办公'
}]
}
},
methods: {
btnclick(item) {
// 子组件发射一个事件
this.$emit('item-click', item);
}
}
}
const app = new Vue({
el: '#app',
data: {
message: '你好啊'
},
components: {
cpn
},
methods: {
cpnClick(item) {
console.log('这里是vue对象的log', item);
}
}
})