ES6中
let定义变量,const定义常量
var没有作用域的概念,所以慢慢不用它了
创建了一个Vue的实例,传入了一个对象,这个对象有一个参数,用于挂载元素
将div交给new Vue管理,解析div中的语法,发现有一个变量message,在data里查找有没有定义,如果有定义,会将内容进行显示
<div id="app">{{message}}</div>
<script>
const app = new Vue({
el: '#app', //用于挂载要管理的元素
data: { //定义数据
message: '你好呀'
}
})
</script>
Vue:声明式编程,可以做到数据与界面完全分离
响应式:数据发生改变时,数据会跟着一起改
<div id="app">
<ul>
<li v-for="items in movies">{{items}}</li>
</ul>
</div>
<script src="js/vue.js"></script>
<script>
const app = new Vue ({
el:'#app',
data:{
movies:['星际穿越','闻香识女人','大话西游','盗梦空间']
}
})
</script>
案例:计数器
Vue一定要挂载一个元素的,所以el属性要写上
语法糖:代码简写
1、@click是v-on:click的语法糖
<div id="app">
<h2>当前计数:{{counter}}</h2>
<button v-on:click="add">+</button>
<button v-on:click="sub">-</button>
</div>
<script src="js/vue.js"></script>
<script>
const app=new Vue({
el:'#app',
data:{
counter:0
},
methods:{
add(){
this.counter++
},
sub(){
this.counter--
}
}
})
</script>
Vue里的MVVM
Vue的option选项
Vue的生命周期
Vue的template
代码规范:缩进2个空格
创建一个Vue的模板(没有做,老师的软件和我的不一样,网上搜的复制代码的内容也和老师不一样,留下来以后做)
插值操作-mustache语法
mustache语法中,不仅仅可以直接写变量,也可以写简单的表达式
<div id="app">
{{message}}
//下面两种显示情况一样
<h2>{{firstName+' '+lastName}}</h2>
<h2>{{firstName}} {{lastName}}</h2>
<h2>{{counter*2}} //输出200
</div>
<script src="js/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
message: '你好呀',
firstName:'Kobe',
lastName:'bryant',
counter:100
},
})
</script>
v-once指令
//在控制台中修改message的值,第一个改变,而第二个不变
<h2>{{message}}</h2>
<h2 v-once>{{message}}</h2>
<div id="app">
<h2>{{url}}</h2> //显示百度一下
<h2 v-html="url"></h2> //显示百度一下的超链接
</div>
data:{
url:'百度一下'
}
v-text指令
一般不同,因为不灵活,如果需要添加文本内容,直接在标签中添加的话,text要显示的内容会直接将添加的内容覆盖
//展示效果相同
<h2>{{message}}</h2>
<h2 v-text="message"></h2>
<h2>{{message}},李银河</h2> //显示你好啊,李银河
<h2 v-text="message">,李银河</h2> //显示你好啊
<h2>{{message}}</h2> //显示你好啊
<h2 v-pre>{{message}}</h2> //显示{{message}}
v-cloak指令
有时网络会卡,div中的{{message}}会直接出现在页面中,而不是显示数据,如果使用setTimeout(const app=new Vue({…}),1000)来延时,会先出现{{message}},下显示message的内容,这种效果不好。此时就可以使用v-cloak
在vue解析之前,div中有一个v-cloak属性,在vue解析之后,会删除v-cloak,div中就没有v-cloak了
在简单项目中,使用 v-cloak 指令是解决屏幕闪动的好方法。但在大型、工程化的项目中(webpack、vue-router)只有一个空的 div 元素,元素中的内容是通过路由挂载来实现的,这时我们就不需要用到 v-cloak 指令
在div还有v-cloak属性时,div中的内容被隐藏,当vue对div解析之后,会自动删除v-cloak,此时div的内容显示
<style>
[v-cloak]{
display:none;
}
</style>
<div id="app" v-cloak>
<h2>{{message}}</h2>
</div>
v-bind指令
语法糖:直接写冒号
mustache{{}}语法是在元素的内容区使用,不能在标签内使用
<img src="{{imgURL}}" alt="">
<img src="{{imgURL}}" alt="">
//上面都是错误的写法,并没有添加上地址
<img v-bind:src="imgURL" alt="">
<a :href="aHref">百度一下</a> //语法糖的写法
data: {
message: '你好呀',
imgURL:'https://cn.vuejs.org/images/lifecycle.png',
aHref:'http://www.baidu.com'
},
v-bind动态绑定class对象语法
:class="{类目:boolean}"
一个括号表示对象,当boolean为true时,对应的类会添加给元素,为false时不会被添加,所以可以通过控制boolean来控制是否有某个类
此时的代码显示为红色字体的你好吗,在控制台输入app.isActive=false,字体变为黑色。代码显示<\h2>的class为空
<style>
.active {
color:red;
}
</style>
<h2 v-bind:class="{active:isActive,line:isLine}"> {{message}} </h2>
//添加一个按钮,点击时可以改变字体的颜色
<button v-on:click="btnclick">按钮</button>
<h2 class="title" v-bind:class="{active:isActive,line:isLine}"> {{message}} </h2> //回将title与后面绑定的class合并
data: {
message: '你好呀',
isActive:true,
isLine:false
}
methods: {
btnclick:function(){
this.isActive=!this.isActive;
}
}
<h2 v-bind:class="getClasses()"> {{message}} </h2>
//将class放在函数里
methods: {
btnclick:function(){
this.isActive=!this.isActive;
},
getClasses:function(){
return {active:this.isActive,line:this.isLine}
}
}
v-bind动态绑定class数组语法
用的不多,因为将class写固定了,如果写固定class可以直接class=“ ”
如果class中的类名是一个从服务器传来数据的变量,那么需要将单引号去掉,这样就会将class中的内容当作变量解析
也可以将数组放在一个methods里
<h2 class="title" :class="['active','line']"> {{message}}</h2> //控制台显示h2的class:title active line
<h2 class="title" :class="getClasses"> {{message}}</h2> //控制台显示h2的class:title aaa bbb
data:{
message:'你好啊',
active:'aaa',
line:'bbb'
}
<h2 class="title" :class="[active,line]"> {{message}}</h2> //控制台显示h2的class:title aaa bbb
data:{
message:'你好啊',
active:'aaa',
line:'bbb'
}
methods:{
getClasses:function(){
return [this.active,this.line]
}
}
v-for与v-bind结合
<\li v-for=“变量(可以随便起名字) in 列表(数组名)”>
要循环哪个标签就将v-for放入哪个标签中
练习:列表点击哪个就变红色
下面是错误的,但是还没清除为什么错
<div id="app">
<ul>
<li v-bind:class="getActive()" v-for="m in movies" v-on:click="liClick">{{m}}</li>
</ul>
</div>
<script src="js/vue.js"></script>
<script>
const app = new new Vue({
el:'#app',
data:{
movies:["海王","海尔兄弟","火影忍者","进击的巨人"]
},
methods: {
getActive:function(){
this.active;
},
liClick:function(){
return this.active=!this.active;
}
}
})
</script>
<div id="app">
//对象语法:下面的显示情况一样
<h2 :style="{fontSize:'50px'}"> {{message}} </h2>
<h2 :style="{fontSize:finalSize1}"> {{message}} </h2>
<h2 :style="{fontSize:finalSize2+'px'}"> {{message}} </h2>
<h2 :style="getStyle()"> {{message}} </h2>
//数组语法
<h2 :style="[baseStyle,baseStyle1]"> {{message}} </h2> //同时显示baseStyle和baseStyle1设置的样式
</div>
<script src="js/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
message: '你好呀',
finalSize1:'50px'
finalSize2:50
0
baseStyle:{backgroundColor:'red'},
baseStyle1:{fontsize:'100px'}
},
methods:{
getStyle:function(){
return {fontSize:this.finalSize2+'px'};
}
})
</script>
计算属性
computed计算属性,是将fullName作为一个属性去使用的,所以使用时不需要添加()
<div id="app">
<h2>{{firstName+' '+lastName}}</h2>
<h2>{{firstName}} {{lastName}}</h2>
<h2>{{fullName}}</h2>
</div>
const app = new Vue({
el: '#app',
data: {
firstName:'Kobe',
lastName:'bryant'
},
computed:{
fullName:function(){
return this.firstName+ ' '+ this.lastName
}
}
})
<div id="app">
总价格:{{totalPrice}}
</div>
<script src="js/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
books:[
{id:110,name:"代码大全",price:100},
{id:110,name:"深入理解计算机原理",price:88},
{id:110,name:"现代操作系统",price:110}
]
},
//computed计算属性,是将fullName作为一个属性去使用的,所以使用时不需要添加()
computed: {
totalPrice: function () {
let result=0;
for(let i=0;i<this.books.length;i++){
result+=this.books[i].price;
}
return result;
}
}
})
</script>
计算属性setter和getter
计算属性一般没有set方法,这样的或这就是一个只读属性
//计算属性的完整写法
computed:{
fullName:{
/* set:function(){
console.log("Lebron James"); //控制台输入app.fullName='abc',显示Lebron James
}
set :function(newName){
this.firstName=newName.split(' ')[0];
this.lastName=newName.split(' ')[1]; //fullName也随之改变,这样的话在控制台中输入Lebron James ,页面中会显示Lebron James
},
一般不用,所以删除掉
*/
get:function(){
return this.firstName+' '+ this.lastName;
}
}
}
//简化写法
computed:{
fullName:function(){
return this.firstName+' '+ this.lastName;
}
}
}
计算属性和methods的对比
通过之前的学习,输出姓名有3中方法
1、直接拼接(语法过于繁琐,一般不采用)
<\h2>{{message}}
2、通过定义methods
<\h2>{{getFullName()}}
3、通过computed
<\h2>{{fullName}}
我们常用第3种方法,多次调用,第二种方法也会执行多次,第三种则只执行一次,因为Vue内部对计算属性做了缓存,如果数据没有变化则会直接返回。所以如果是对数据做一些变化再展示时选择第二种方法较好
ES6的补充
变量作用域:变量在什么范围内是可用
ES5之前因为if和for都没有块级作用域的概念,所以在很多时候,我们都必须借助于function的作用域来解决引用外部变量的问题。ES6种加入了let,let是有if和for的块级作用域的
<button>按钮1</button>
<button>按钮2</button>
<button>按钮3</button>
<button>按钮4</button>
var btn = document.getElementsByTagName("button");
for(let i =0;i<btn.length;i++){ //如果此处是var,则无论点击哪个按钮都会弹出第3个。闭包也可以解决这个问题,因为函数是一个作用域。在JS种,只有函数是有作用域的
btn[i].onclick=function(){
console.log("第"+i+"个按钮被点击了");
};
}
const
一旦const修饰的标识符被赋值后,不能再修改const的值
使用const定义标识符时,必须进行赋值
常量的含义是指向的对象不能修改,但是可以改变对象内部的属性,如定义一个obj,含有属性name:‘kobe’,用obj.name=‘why’可以改变name的值,不会报错
自己的理解:用const定义一个常量,是将值保存在栈内存中,const保存的是该值的地址,所以如果再将其他的任何数据类型的值重新赋给该常量,也就是将另外一个地址赋给它,这样是不允许的,所以会报错。
而如果const定义的是一个常量对象,对象中包含着属性名和属性值,这些属性名和属性值都是在同一个地址内存里的,修改属性值的操作是在内存内部完成的,也就是将地址中的值改变为另一个值,不涉及其他内存地址,所以可以改变对象内部的属性。
对象字面量的增强写法
1、属性的增强写法
const name='why';
const age= 18;
const height=1.88;
//const obj = {}; //一开始我是先声明,后面再去给obj添加属性的,犯了const不能再次赋值的错误,所以应该去掉这一行,在声明时同时定义obj
//如果想要将name、age、height放在obj里保存
//ES5中的写法
const obj={
name='why';
age= 18;
height=1.88;
}
//ES6中的写法,会直接将变量的名称作为key,将变量具体的值作为value
const obj={
name,
age,
height
}
2、函数的增强写法
//ES5中给对象定义函数
const obj = {
run:function(){
},
eat:function(){
}
}
//ES6中的增强写法
const obj ={
run(){
},
eat(){
}
}
事件监听
v-on的基本使用
如果函数需要参数,但是没有传入,那么函数的形参为undefined
function abc(abc){
console.log(name); //输出undefined
}
abc();
在事件定义时,写方法/函数时省略了小括号,但是方法本身是需要一个参数的,这时,Vue会默认将浏览器生成的event事件对象作为参数传到函数中。所以当需要获取event对象时,是将形参设置为event,不传入任何实参,直接在方法/函数中使用event
需要传入参数时
1、正常传入参数
2、写()但是不传入参数
3、不传参数也不写()
<button @click="btnClick(abc)">按钮</button> //输出lalala,abc
<button @click="btnClick()">按钮</button> //输出lalala,undefined
<button @click="btnClick">按钮</button> //输出一个鼠标事件MouseEvent
methods:{
btnClick(name){
console.log("lalala",name);
}
需要传入参数,同时需要event时
1、没有括号,也不传入参数
2、传入(123,event),此时123是作为一个数字解析赋值给abc,而event没有引号,浏览器会将它当作一个变量,但是代码里并没有声明定义event,所以会报错,并返回undefined
3、传入(123,),不传入第二个参数,不报错,直接返回undefined
4、在调用方法时,手动的获取到浏览器参数的event对象:$event
<button @click="btnClick">按钮</button> //输出dididi,鼠标点击事件,undefined
<button @click="btnClick(123,event)">按钮</button> //输出 dididi,123,undefined,并且报错
<button @click="btnClick(123,event)">按钮</button> //输出 dididi,123,undefined,不报错
<button @click="btnClick(123,$event)">按钮</button> //输出 dididi,123,鼠标点击事件
methods:{
btnClick(abc,event){
console.log("dididi",abc,event);
}
}
v-on修饰符
.stop 修饰符可以取消冒泡,
点击按钮时,因为事件冒泡,所以会控制台会输出btnClick和divClick
@click.stop 可以取消冒泡
<div @click="divClick">
<button @click="btnClick"></button>
<button @click.stop="btnClick"></button>
</div>
methods:{
divClick(){
console.log("divClick");
},
btnClick(){
console.log("btnClick");
}
}
.prevent 阻止默认行为。如提交表单,添加后点击提交并不能提交成功
点击a标签,控制台输出aClick但是并不跳转到百度页面
<a href="http://www.baidu.com" @click.prevent="btnClick">lalala</a>
methods:{
aClick(){
console.log("aClick");
}
}
.{keyCode|keyAlias} 监听键盘按键
<input type="text" @keyup="keyUp" /> //每按下一个按键,输出keyup一次
<input type="text" @keyup.enter="keyUp" /> //监听enter,只有enter被按下时,才输出keyup
methods:{
keyUp(){
console.log("keyup");
}
}
.once 只触发一次回调
<button @click.once="btnClick"></button> //点击一次输出btnclick后再点击不会再输出
methods:{
btnClick(){
console.log("btnClick");
}
}
<h2 v-if="isTrue"> lalala </h2>
<h2 v-else>dididi 是false </h2>
//在控制它修改app.isTrue=false,显示dididi 是false
data: {
isTrue:true
},
条件渲染案例
label中的for,如果和input的id相同,那么点击label的内容时,输入框会自动成为输入状态
这个案例是直接将所有内容都替换,我想的是改变文本内容即可,复习时可以重新做一做
<span v-if="isUser">
<label for="username">用户账号:</label>
<input type="text" id="username" placeholder="用户名登录"/>
</span>
案例深入讲解
输入用户名后点击按钮,换成了邮箱登录,但是文本框中的内容没有被清除,是因为虚拟dom
添加key,浏览器会将key作为一个标识来判断能不能复和,如果key相同,可以复用,不同则不能复用。不能复用后就会创建一个新的input
<input type="text" id="username" placeholder="用户名登录" key="username"/>
<input type="text" id="username" placeholder="用户名登录" key="email"/>
v-show
v-show 是控制节点的display样式,display:none
v-if 如果值为false则是将节点删除了
如果节点需要频繁显示/隐藏,使用v-show性能更好
<h2 v-if="isShow" id="aaa">{{message}}</h2>
<h2 v-show="isShow" id="bbb">{{message}}</h2>
//在控制台中输入app.isTrue=false,会发现第一个h2不存在了,而第二个多了个display:none的样式
data:{
isTrue:true
}
循环遍历
遍历数组
1、遍历过程中,不涉及索引值
2、输出名字序号
<ul>
<li v-for="item in names">{{item}}</li>
</ul>
<ul>
<li v-for="(item,index) in names">{{index+1}}.{{item}}</li>
</ul>
data:{
names:['why','kobe','james','curry']
}
遍历对象
1、在遍历对象的过程中,如果只获取一个值,那么获取到的是value
2、获取key和value 格式:(value,key)
3、获取key、value和index 格式(value,key,index)
<ul>
<li>{{info.name}}</li>
<li>{{info.age}}</li>
<li>{{info.height}}</li>
</ul>
<ul>
<li v-for="item in info">{{item}}</li> //依次输出info的属性值
<li v-for="(value,key) in info">{{value}}--{{key}}</li> //依次输出value--key
<li v-for="(value,key,index) in info">{{value}}--{{key}}--{{index}} </li> //依次输出value--key--index
</ul>
data:{
info:{
name:'why',
age:18,
height:1.88
}
}
v-for绑定或不绑定key的区别
理解的不够清楚,复习时可以再看看
没有key的话,如果在数组第二个元素后插入一个值,并不是创建一个新的li放在2后面,而是新的值直接占用第三个li,后面依次往后推,性能较低
<ul>
<li v-for="item in names" :key="item">{{item}}</li> //要保证key和展示的元素是一一对应的
</ul>
data:{
names:['why','kobe','james','curry']
}
数组发生变化是,因为数据是响应式的,所以页面能自动刷新数据
Vue内部会监听数据变化,然后根据新的数据重新渲染dom。本质上是重新渲染出虚拟dom,然后根据虚拟dom把真实dom进行修改
push()、unshift() 可以一次添加多个元素
...num 可变参数,不限制输入参数的个数
```javascript
function sum(...num){
console.log(num); //输出Array[9]
}
sun(10,20,30,40,50,60,70,80,90);
push的源码,和可变参数形式很像,所以可以传入多个参数
splice() 可以删除元素/插入元素/替换元素
参数:
1、第1个参数是从第几个元素开始操作
2、如果没有第3个参数,那么第2个参数是删除元素的个数(如果不传就会删除所有)。如果有第3个参数,那么第2个参数是替换元素的个数
3、如果第2个参数不为0,那么第三个参数及以后表示要替换的内容,如果第2个参数为0,那么第三个参数及以后表示要插入的内容
源码:数字、数字、可变参数
通过索引值修改数组中的元素并不是响应式的(弹幕说现在可以了?以后试试)
this.letter[0]=“aaaaaa”;
this.letter.splice(0,1,‘aaaaaa’);
Vue中有一个专门修改数组的方法set()
参数:
1、要修改的对象
2、索引值
3、修改后的值
Vue.set(this.letters,0,‘aaaaaa’);
点击电影名后变色的练习:
1、首先遍历数组,v-for将数组展示出来,因为后面需要判断是哪个元素被点击,所以还需要获取到每个元素的索引
2、声明一个变量,用来记录是哪个元素被点击
3、给每个元素绑定class类,如果被点击的是当前的元素,则类值为true,所以是判断之前声明用来记录的变量是否与该元素的index相同
4、监听是哪个元素被点击,给每个元素添加点击事件,需要传入index参数,表示该元素被点击。点击事件中,将index赋值给之前声明的变量
案例:购物车 3
1、遍历表格的每一栏可以使用v-for,但是遍历每一栏中的信息最好不要用v-for,因为每一栏中有些东西需要单独设置其他内容,如数量有两个按钮可以增加或者减少,如价格是保留两位小数等
toFixed() 保留小数,参数为保留小数的位数
filters:过滤器,在option里面定义。将要过滤的值作为参数传入(不大明白有什么用,以后找资料看)
filters:{
showPrice(price){
return '¥'+price.toFixed(2);
}
2、修改count时,需要找到哪一本书的count被修改,所以还需要获取item的index,将index传入点击函数,修改index相对应的count
3、count值最小为1,当count小于1时,应该将button设置为disabled。所以给button用v-bind绑定就可以
4、如果购物车为空则显示购物车为空的字,所以需要在table外加上判断,books.length是否为0
5、计算价格的几种方法
(1)普通的for循环
(2)for(let i in this.books),i为索引值
(3)for(let item of this.books),item为数组中的元素
(4)reduce
finalPrice(){
let finalPrice=0;
for(let i=0;i<this.books.length;i++){
finalPrice+=this.books[i].price*this.books[i].count;
}
return finalPrice;
}
let finalPrice=0;
for(let i in this.books){ //i为索引值
finalPrice+=this.books[i].price*this.books[i].count;
}
return finalPrice;
let finalPrice=0;
for(let item of this.books){ //item为数组中的元素
finalPrice+=item.price*item.count;
}
return finalPrice;
编程范式的划分:命令式编程/声明式编程
面向对象编程(第一公民:对象)/函数式编程(第一公民:函数)
高阶函数:filter/map/reduce(函数需要的参数可能也是一个函数)
传统实现需求的流程:
高阶函数做法:
1、先对所有数字过滤
filter中的函数有一个要求,必须返回boolean值
当返回true时,函数内部会自动将这次回调的n加入到新的数组中
,返回false时,函数内部会过滤掉这次的n。函数的返回值是那个新的数组
2、map函数的使用
3、reduce(function(preValue,n){return 100},0)函数的使用,对数组中所有的内容进行汇总
第一次:preValue:0,n:20
第二次:preValue:100,n:40
第三次:preValue:100,n:80
第四次:preValue:100,n:100
let newNums=nums.filter(function(n){ //回调函数在每遍历一个数字时执行一次,数值中有7个值,所以会回调7次
return n<100;
}) //newNums[10,20,40,50]
let new2Nums =newNums.map(function(n){
return n*2; //如果的是return 100; 则会输出4个100,因为回调函数会遍历4次
}) //new2Nums[20,40,80,100]
let total = new2Nums.reduce(function(preValue,n){
return preValue+n;
},0)
/*
第一次:preValue:0,n:20,返回:20
第二次:preValue:20,n:40,返回:60
第三次:preValue:60,n:80,返回:140
第四次:preValue:140,n:100,返回:240
*/
//和在一起写(函数式编程)
let total = nums.filter(function(n){
return n<100;
}).map(function(n){
return n*2;
}).reduce(function(preValue,n){
return preValue+n;
},0)
//更简略的写法(箭头函数)
let total = nums.filter(n=>n<100).map(n=>n*2).reduce((pre,n)=>pre+n);