本章目录
19-22.购物车案例-(界面搭建、过滤器的使用、改变购买数量、移除按钮-最终价格)
1.计算属性setter和getter
computed属性默认是下面是这样的,但是它是有Get 和 Set属性的
<script>
const app = new Vue({
el:'#app',
data:{
FirstName:'AA',
lastName:'BB'
},
computed:{
fullName:function(){
return this.FirstName + ' '+ this.lastName;
}
}
})
</script>
get和set属性
<div id="app">
<h4>{{fullName}}</h4>
</div>
<script>
const app = new Vue({
el:'#app',
data:{
FirstName:'AA',
lastName:'BB',
},
computed:{
// fullName:function(){
// return this.FirstName + ' '+ this.lastName;
// }
fullName:{
set:function(newValue){
console.log('---',newValue);
const name = newValue.split(' ');//空格切割字符串
this.FirstName = name[0];
this.lastName = name[1];
},
get:function(){
return this.FirstName + ' '+ this.lastName;
}
}
}
})
</script>
2.计算属性和methods的对比
页面同时调用多次方法和计算,方法会调用多次,计算只会调用一次,性能更高
主要原因是因为计算内部有缓存,会把刚才的操作缓存下来,而方法不会,只会重复调用,影响性能
<div id="app">
{{full()}}
{{full()}}
{{full()}}
{{full()}}
{{full()}}
{{fullName}}
{{fullName}}
{{fullName}}
{{fullName}}
{{fullName}}
</div>
<script>
const app = new Vue({
el:'#app',
data:{
firstName:'qixiannv',
lastName:'dongyong',
},
methods:{
full:function(){
console.log('full');
return this.firstName;
}
},
computed:{
fullName:function(){
console.log('fullName');
return this.lastName;
}
}
})
</script>
3.块级作用域-let和var
let:可变变量 (块级作用域:{}变量在什么范围内可用) const:不可变变量
var:全局变量
没有块级作用域引发的问题
(1)if的块级(var变量没有块级作用域,定义在局部的变量被外面同名的变量更改了)
//1.没有块级作用域引发的问题:if的块级
var func;
if(true)
{
var name = 'why';
func = function(){
console.log(name);
}
}
name = 'lyf';
func();
console.log(name);
(2)for的块级
<button type="button">按钮</button>
<button type="button">按钮</button>
<button type="button">按钮</button>
<button type="button">按钮</button>
<button type="button">按钮</button>
var btn = document.getElementsByTagName('button');
for(var i =0;i<btn.length;i++)
{
console.log('第'+ i +'个按钮被点击');
}
闭包:函数是一个作用域,i在其中,不会被别的改掉
var btn = document.getElementsByTagName('button');
for(var i =0;i<btn.length;i++)
{
(function(i){
btn[i].addEventListener('click',function(){
console.log('第'+ i +'个按钮被点击');
})
})(i)
}
var name ='aa';
function abc(name){
console.log(name);//输出的是abc,优先输出自己作用域的内容
}
abc('123');
var name ='bbb';
(3)用let执行 let有块级作用域
4.三种方案对比-ES5没有闭包-有闭包-ES6的let
es5没有块级作用域,采用闭包的方法可以避免变量污染,而es6中有块级变量域,很好的解决了这个问题
var btn = document.getElementsByTagName('button');
for(var i =0;i<btn.length;i++)
{
console.log('第'+ i +'个按钮被点击');
}
es5的闭包(没有作用域,i会泄露为全局变量,有作用域,互不干扰)
var btn = document.getElementsByTagName('button');
for(var i =0;i<btn.length;i++)
{
(function(i){
btn[i].addEventListener('click',function(){
console.log('第'+ i +'个按钮被点击');
})
)(i)//作用域中又属于自己的i,不被外面的i影响
}
(3)用let执行 let有块级作用域
(4)es6中有块级作用域了,不用像es5那样需要闭包了
5.const的使用和注意点
使用const修饰的标识符为常量,不可以再次赋值
(1)赋值之后,不可修改
<script>
//注意1:一旦给const修饰的标识符被赋值之后,不能修改
const name ='aa';
name ='nn';
</script>
(2)定义const常量后必须赋值
<script>
// 注意2:在使用const定义标识符,必须进行赋值
// const name;
</script>
(3)指向对象不可修改,可以改变对象内部属性
<script>
// 注意3:常量的含义是指向的对象不能修改,但是可以改变内部的属性
const obj = {
name:'lyf',
age:5,
color:'pink',
func:function(){
console.log('walyf');
}
}
console.log(obj);
obj.name='hg';
obj.age = 18;
obj.color = 'green';
obj.func();
console.log(obj);
</script>
const内存地址不可修改
eg:(括号内为变量的内存地址)
const (#x01) obj(#x01)
再次修改(#x02) obj(#x02),则会报错,const内存地址不可修改
但是如果改变内部属性是可以的,因为没有改变到const变量的内部地址
const (#x01) obj(#x01)-> name (name为obj对象的内部属性)
6.ES6对象字面量增强写法
const obj = new object();
简写:const obj = {} ({} 大括号表示对象字面量)
// const obj = new object();
const obj = {
name :'lyf',
age:18,
run:function(){
console.log('lyf run');
},
eat:function(){
console.log('lyf eat');
},
}
obj.run();obj.eat();
es5和es6的写法(es6为增强写法)
(1)属性的增强写法
const name = 'lyf';
const age = 18;
//1.es5写法
// const obj = {
// name:name,
// age:age,
// }
//2.es6写法
const obj = {
name,
age,//直接写对象名,就直接把同名的变量名赋进去
}
console.log(obj);
console.log(obj.age);
(2)方法的增强写法
//2.方法的增强写法
//(1)es5写法
const obj = {
func:function(){
console.log('walyf');
}
}
//(2)es6写法
const obj = {
func(){
console.log('wyahg');
}
}
obj.func();
(3)javascript没有类型推测
8.v-on的基本使用和语法糖
(1)点击进行加减计算
<div id="app">
<h1 :style="{color:'#c00'}">{{computer}}</h1>
<!-- <button v-on:click="computer++">+</button>
<button v-on:click="computer--">-</button> -->
<button v-on:click="getCom">+</button>
<button v-on:click="deCom">-</button>
</div>
<script>
const app = new Vue({
el:'#app',
data:{
computer: 0
},
methods:{
getCom(){
this.computer++;
},
deCom(){
if(this.computer>1)
{
this.computer--;
}
}
}
})
</script>
(2)语法糖 :v-on:click @click
9.v-on的参数传递问题
(1)没有参数的情况下,()括号可以省略
(2)如果函数需要参数,但没有传入,那么函数的形参为undefined
如果函数不需要传入参数,那么括号()可以省略
如果是js的话,方法中需要参数,没有传入也会报undefined错误
eg:function abc(name) {} abc(); ~~~ undefined
<div id="app">
<button @click="btnClick">按钮1</button><!--如果函数不需要传入参数,那么括号()可以省略-->
<!--在事件定义时,写函数时忽略了小括号,但是方法本身是需要一个参数的,这个时候如果没有传参数进去会报undefined错误-->
<button @click="btnClick2">按钮2</button><!--错误-->
<button @click="btnClick2('hg')">按钮2</button><!--正确-->
</div>
<script>
const app = new Vue({
el:'#app',
data:{
computer: 0
},
methods:{
btnClick(){
console.log('walyf666');
},
btnClick2(h){
console.log('wa'+h+'666');
}
}
})
</script>
(3)在事件定义时,写方法时省略了小括号,但方法本身是需要一个参数的,这个时候Vue会默认将浏览器生成的event对象作为参数传入方法中
<div @click="onclick">按钮</div>
methods:{
onclick(event){
alert(event);//event中有对象参数
}
}
(4)需要event参数,也需要其他参数
<!--方法定义时,我们需要event对象,同时又需要其他参数-->
<!--在调用方法,如何手动的获取到浏览器参数的event对象:$event-->
<div @click="btn3('123',$event)">按我</div>
btn3(abc,event){
alert(abc);
alert(event);
}
10.v-on的修饰符使用
(1)@click.stop
事件冒泡:事件冒泡的走向是由父节点向子节点去触发同名事件
<div id="app">
<!--事件冒泡:事件冒泡的走向是由父节点向子节点去触发同名事件-->
<button @click="btnClick">
<!-- <div @click="divClick">按我</div> -->
<!--@click.stop阻止事件冒泡-->
<div @click.stop="divClick">按我</div>
</button>
</div>
<script>
const app = new Vue({
el:'#app',
data:{
},
methods:{
btnClick(){
console.log("aa");
},
divClick(){
console.log("bb");
}
}
})
</script>
(2)@click.prevent(阻止服务器自动提交)自己定义提交方式,点击自动提交
<div id="app">
<form action="?">
<input type="submit" value="提交" @click.prevent="submitBtn">
</form>
</div>
<script>
const app = new Vue({
el:'#app',
data:{
},
methods:{
submitBtn(){
console.log('sub');
}
}
})
</script>
(3)@keyup监听键盘某个按钮的点击
<div id="app">
<input type="text" @keyup.enter="keyups"/><!--回车-->
</div>
<script>
const app = new Vue({
el:'#app',
data:{
},
methods:{
keyups(){
console.log('hgg');
}
}
})
</script>
(4)@click:once:方法只调用一次
<div id="app">
<button @click.once="btnSubmit">按钮</button>
</div>
<script>
const app = new Vue({
el:'#app',
methods:{
btnSubmit(){
console.log('lyff');
}
}
})
</script>
11.v-if和v-else-if和v-else的使用
(1)v-if和v-else
<div id="app">
<!--为true时显示div内容-->
<!--1.-->
<div v-if="false">
{{message}}
</div>
<!--2.-->
<div v-if="isshow">
{{message}}
</div>
<div v-else>
isshow为false显示我
</div>
</div>
<script>
const app = new Vue({
el:'#app',
data:{
message:'lyfihg',
isshow:false,
},
methods:{
}
})
</script>
(2)v-else -if(复杂时,用compted计算属性) v-else -if与compted对比
<div id="app">
<div v-if="score>=90">优秀</div>
<div v-else-if="score>=80">良好</div>
<div v-else-if="score>=60">及格</div>
<div v-else>不及格,仍需努力!</div>
</div>
<script>
const app = new Vue({
el:'#app',
data:{
score:95,
}
})
</script>
<div id="app">
<div v-if="score>=90">优秀</div>
<div v-else-if="score>=80">良好</div>
<div v-else-if="score>=60">及格</div>
<div v-else>不及格,仍需努力!</div>
<div>{{sum}}</div>
</div>
<script>
const app = new Vue({
el:'#app',
data:{
message:'lyfihg',
isshow:false,
score:92,
},
computed:{
sum(){
let msg = "";
if(this.score>=90)
{
msg = "优秀";
}
else if(this.score>=80)
{
msg = "良好";
}
else if(this.score>=60)
{
msg = "及格";
}
else{
msg = "不及格,仍需努力!";
}
return msg;
}
}
})
</script>
12.登录切换的小案例
<div id="app">
<span v-if="ischeck">
<label for="username">用户账号</label>
<input id="username" key="username"
><!--label的for和input的id名称相同,点击labelinput的文本框会聚焦-->
</span>
<span v-else>
<label for="userEmail">用户邮箱</label>
<input id="userEmail" key="userEmail">
</span>
<input value="点击切换" @click="ischeck=!ischeck" type="button">
</div>
<script>
const app = new Vue({
el:'#app',
data:{
ischeck:true,
},
methods:{
}
})
</script>
13.登录切换的input复用问题
Vue进行Dom渲染时,出于性能考虑,会尽可能复用存在的元素
复用解决:在标签中加一个key属性,表明这是唯一元素
<span v-if="ischeck">
<label for="username">用户账号</label>
<input id="username" key="username"/>
</span>
<span v-else>
<label for="userEmail">用户邮箱</label>
<input id="userEmail" key="userEmail"/>
</span>
14.v-show的使用以及和v-if的区别
切换频率高:v-show
只有一次切换:v-if
<div id="app">
<!--v-if:当条件为false时,包含v-if指令的元素,根本不会存在dom中(元素被删除)-->
<div v-if="isshow" id="aa">{{message}}</div>
<!--v-show:当条件为false时,v-show只是给我们的元素添加一个行内样式:display:none;-->
<div v-show="isshow" id="bb">{{message}}</div>
</div>
<script>
const app = new Vue({
el:'#app',
data:{
message:'who is me?',
isshow:false,
}
})
</script>
15.v-for遍历数组和对象
(1)遍历数组
<div id="app">
<!--1.在遍历的过程中,没有使用索引值(下标值)-->
<ul>
<li v-for="item in name">{{item}}</li>
</ul>
<!--2.在遍历的过程中,获取索引值(下标值)-->
<ul>
<li v-for="(item,index) in name">{{index}}~~~{{item}}</li>
</ul>
</div>
<script>
const app = new Vue({
el:'#app',
data:{
name:['who','is','me','zjh'],
}
})
</script>
(2)遍历对象
<div id="app">
<!--遍历对象-->
<ul>
<li v-for="item in info">{{item}}</li><!--一个输出的是值(value)-->
</ul>
<ul>
<li v-for="(value,key) in info">{{key}}~~{{value}}</li>
<!--两个输出的是值,键(value,key)-->
</ul>
<ul>
<li v-for="(value,key,index) in info">{{index}}~~{{key}}~~{{value}}</li>
<!--三个输出的是值,键,索引(value,key,index)-->
</ul>
</div>
<script>
const app = new Vue({
el:'#app',
data:{
name:['who','is','me','zjh'],
info:{
name:'lyf',
age:'18',
Love:'hg',
sex:'girl',
}
}
})
</script>
16.v-for-绑定和非绑定key的区别
首先,它们区别主要在于 虚拟DOM的复用,绑定key可以更好的复用(遍历用key标识速度会提升)
没有绑定key:在插入的数据之后的数据全部会被更新
绑定key:原本的数据key不变,只是挪用了一下位置,把现在要操作的数据插入进去
假如我们有一个数组 arr = [1,2,3,4],我们要在2后面插入一个值9;
如果绑定了key值,那么会是这样的情况:
如果没有绑定key值,那么会是这样的情况:
17.数组中哪些方法是响应式的
1.push()方法(追加到元素最后)
//1.push方法
this.latter.push('1','2');
//2.通过索引值修改数组中的元素
this.latter[0]="aaa";
console.log(this.latter);
2.pop():删除数组中最后一个元素
this.latter.pop();
3.shift():删除数组中第一个元素
this.latter.shift();
4.unshift():在数组最前面添加元素
this.latter.unshift('aa');
5.splice():删除元素/插入元素/替换元素
// (1)删除元素:第二个元素传入你要删除几个元素(如果没有传,就删除后面所有的元素)
this.latter.splice(1,1);//删除第一个后面的值
this.latter.splice(1);//只传入一个,表示删除第一个后面的所有值
// (2)替换元素:第二个参数,表示我们替换几个元素,后面是用于替换前面的元素
this.latter.splice(1,3,'m','n','l','x');
// (3)插入元素:第二个参数,传入0,并且后面跟上要插入的元素
this.latter.splice(1,0,'m','n','l','x');
6.sort():排序
this.latter.sort();
7.reverse()反转
this.latter.reverse();
// 注意:通过索引值修改数组中的元素(不是响应式)
// (1)this.latter[0]="asda";(不是响应式)
// (2)this.latter.splice(0,1,'ccc');通过替换(响应式)
8.set(要修改的对象,索引值,修改后的值)
Vue.set(this,latter,0,'eeeee');
18.作业的回顾和实现
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<script src="../vue.js"></script>
<title></title>
<style>
.red{color:#c00;}
</style>
</head>
<body>
<div id="app">
<ul>
<li v-for="(item,index) in movers" @click="onclick(index)" :class={red:active===index}>
{{index}}-{{item}}
</li>
</ul>
</div>
<script>
const app = new Vue({
el:'#app',
data:{
movers:['还珠格格','放羊的星星','天国的嫁衣'],
active :0,
},
methods:{
onclick(index){
this.active = index;
}
}
})
</script>
</body>
</html>
19-22.购物车案例-(界面搭建、过滤器的使用、改变购买数量、移除按钮-最终价格)
(1)价格保留两位小数:{{item.price.toFixed(2)}}
(2)价格前加¥符号
1.价格前加¥符号:{{'¥'+item.price.toFixed(2)}}
1.方法中传参,加¥:{{getPrice(item.price)}}
methods:{
getPrice(price){
return '¥'+price.toFixed(2);
}
},
2.过滤器: {{item.price|getPrice}}
filters:{//过滤器
getPrice(price){
return '¥'+price.toFixed(2);
}
}
购物车代码如下:
html:
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<script src="../vue.js"></script>
<title></title>
</head>
<body>
<div id="app">
<div v-if="books.length">
<table>
<thead>
<tr>
<th><th>
<th>书籍名称<th>
<th>出版日期<th>
<th>价格<th>
<th>购买数量<th>
<th>操作<th>
</tr>
</thead>
</table>
<table>
<tr v-for="(item,index) in books">
<td>{{item.id}}</td>
<td>{{item.name}}</td>
<td>{{item.date}}</td>
<!-- <td>{{getPrice(item.price)}}</td> -->
<td>{{item.price|getPrice}}</td>
<td>
<!-- <button @click="decrement(index)" v-bind:disabled="item.count<=1">-</button> -->
<button @click="decrement(index)" :disabled="item.count<=1">-</button>
{{item.count}}
<button @click="increment(index)">+</button>
</td>
<td><button @click="removeHandle(index)">移除</button></td>
</tr>
</table>
<h2>总价:{{totalPrice|getPrice}}</h2>
</div>
<h2 v-else>购物车没有东西</h2>
</div>
<script src="min.js"></script>
</body>
</html>
js:
const app= new Vue({
el:'#app',
data:{
books:[
{
id:1,
name:'还珠格格',
date:'1998.01.30',
price:89.23,
count:1
},
{
id:2,
name:'放羊的星星',
date:'2007.01.30',
price:89.00,
count:1
},
{
id:3,
name:'命中注定我爱你',
date:'2010.01.30',
price:89.00,
count:1
},
{
id:4,
name:'海派甜心',
date:'2009.01.30',
price:89.00,
count:1
},
]
},
methods:{
getPrice(price){
return '¥'+price.toFixed(2);
},
increment(index){
this.books[index].count++;
},
decrement(index){
this.books[index].count--;
},
removeHandle(index)
{
this.books.splice(index,1);
}
},
filters:{//过滤器
getPrice(price){
return '¥'+price.toFixed(2);
}
},
computed:{
totalPrice(){
let totalPrice = 0;
for(let i=0;i<this.books.length;i++)
{
totalPrice += this.books[i].price*this.books[i].count;
}
return totalPrice;
}
}
})
2020.4.20-2020.5.3这章节学习的时间跨度有点长啊,还是要继续加油,在学习的过程中越发觉得Vue有魅力,加油
ヾ(◍°∇°◍)ノ゙