Vue 1-- ES6 快速入门、vue的基本语法、vue应用示例,vue基础语法
一、ES6快速入门
let和const
let
ES6新增了let命令,用于声明变量。其用法类似var,但是声明的变量只在let命令所在的代码块内有效。
{
let x = 10;
var y = 20;
}
x // ReferenceError: x is not defined
y // 20
效果如下:
var声明变量存在变量提升。也就是在声明变量之前就可以使用该变量。
console.log(x) // undefined,var声明变量之前可以使用该变量
var x = 10;
刷新页面,粘贴代码,效果如下:
而let不会这样,let声明的变量不能在声明之前使用。
刷新页面,粘贴代码,效果如下:
比如:
function foo(){
let x = 10;
var x = 20;
}
foo(); // 报错
刷新页面,粘贴代码,效果如下:
再比如:
function foo(){
let y = 10;
let y = 20;
}
foo(); // 报错
刷新页面,粘贴代码,效果如下:
var name = 'Q1mi'
function foo(){
console.log(name)
if (false){
var name = 'Bob'
}
}
foo() // undefined
刷新页面,粘贴代码,效果如下:
for (var i=0;i<5;i++){ console.log('哈哈'); } console.log(i); // 5
刷新页面,粘贴代码,效果如下:
var声明的变量会污染全局,所以在for循环外部可以打印i的值。for循环中的i最好使用let声明
ES6中的let声明变量的方式实际上就为JavaScript新增了块级作用域。
var name = 'Q1mi'
function foo(){
console.log(name)
if (false){
let name = 'Bob'
}
}
foo() // Q1mi
刷新页面,粘贴代码,效果如下:
此时,在foo函数内容,外层代码块就不再受内层代码块的影响。所以类似for循环的计数变量我们最好都是用let来声明。
let声明能够将变量限制在当前的块级作用域中
const
const用来声明常量。const声明变量必须立即初始化,并且其值不能改变。
const声明常量的作用域与let相同,只在生命所在的块级作用于内有效
const PI = 3.14;
举例:
const 用来声明一个常量,不能修改
全局对象的属性:
ES6规定:var命令和function命令声明的全局变量依旧是全局对象的属性;let命令、const命令和class命令声明的全局变量不属于全局对象的属性。
查看下面的示例代码:
var x = 10;
let y = 20;
window.x // 10
window.y // undefined
刷新页面,粘贴代码,效果如下:
变量的解构赋值
ES6允许按照一定的模式,从数组或对象中提取值,对变量进行赋值,这种方式被成为解构赋值
var [x, y, z] = [10, 20, 30];
x; //10
y; //20
z; //30
刷新页面,粘贴代码,效果如下:
对象的解构赋值:
var {x, y} = {x: 10, y: 20};
x; // 10
y; // 20
刷新页面,粘贴代码,效果如下:
var和function声明的变量,默认会在windows对象上
let声明的变量默认不会出现在windows对象上
举例:
window.name1输出undefined
函数
箭头函数
箭头函数特点:
1.如果参数只有一个,可以省略小括号
2.如果不写return,可以不屑大括号
3.没有arguments
4.不改变this指向
其中箭头函数中this指向被固定化,不是因为箭头函数内部有绑定this的机制。实际原因是箭头函数根本没有自己的this,导致内部的this就是外层代码块的this
可以查看下面两段代码输出的区别:
var person = {
name: 'Q1mi',
age:18,
func:function(){
console.log(this);
}
}
person.func() // person对象
刷新页面,粘贴代码,效果如下:
和
var person = {
name: 'Q1mi',
age:18,
func:()=>{
console.log(this);
}
}
person.func() // window对象
刷新页面,粘贴代码,效果如下:
但凡用到箭头函数,不要用this
对象
属性简洁表示法
ES6允许直接写入变量和函数作为对象的属性和方法。
function f(x, y){
return {x, y}
}
上面的写法等同于:
function f(x, y){
return {x: x, y: y}
}
对象的方法也可以使用简洁表示法:
var o = {
method(){
return "hello";
}
}
等同于:
var o = {
method: function(){
return "Hello";
}
}
刷新页面,粘贴代码,效果如下:
Object.assign()
Object.assign方法用来将源对象(source)的所有可枚举属性复制到目标对象(target)。它至少需要两个对象作为参数,第一个参数是目标对象,第二个参数是源对象。
参数必须都是对象,否则抛出TypeError错误。
Object.assjgn只复制自身属性,不可枚举属性(enumerable为false)和继承的属性不会被复制。
简单示例:
var x = {name: "Q1mi", age: 18};
var y = x;
var z = Object.assign({}, x);
x.age = 20;
x.age; // 20
y.age; // 20
z.age; // 18
刷新页面,粘贴代码,效果如下:
注意:
Object.assign方法的其他用处,可查看文末链接。
面向对象:类
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <form action="" method="post"> <input type="text" name="name"> <input type="submit" value="提交"> </form> <script> // 定义一个构造函数 function Point(x, y){ this.x = x; this.y = y; } // 给父级绑定方法 Point.prototype.toSting = function(){ return '(' + this.x + ',' + this.y + ')'; }; // 生成一个Point对象 var p = new Point(10, 20); console.log(p.x); console.log(p.toSting()); // 继承 function ColorPoint(x, y, color){ Point.call(this, x, y); this.color = color; } // 继承父类的方法 ColorPoint.prototype = Object.create(Point.prototype); // 修复 constructor ColorPoint.prototype.constructor = Point; // 扩展方法 ColorPoint.prototype.showColor = function(){ console.log('My color is ' + this.color); }; var cp = new ColorPoint(10, 20, "red"); console.log(cp.x); console.log(cp.toSting()); cp.showColor(); </script> </body> </html>
刷新页面,效果如下:
ES6 使用Class构造对象的方式:
修改test.html,js代码如下:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <form action="" method="post"> <input type="text" name="name"> <input type="submit" value="提交"> </form> <script> class Point{ constructor(x, y){ this.x = x; this.y = y; } // 不要加逗号 toSting(){ return `(${this.x}, ${this.y})`; } } var p = new Point(10, 20); console.log(p.x); p.toSting(); class ColorPoint extends Point{ constructor(x, y, color){ super(x, y); // 调用父类的constructor(x, y) this.color = color; } // 不要加逗号 showColor(){ console.log('My color is ' + this.color); } } var cp = new ColorPoint(10, 20, "red"); console.log(cp.x); cp.toSting(); cp.showColor(); </script> </body> </html>
刷新页面,效果如下:
二、Vue
1、vue的介绍
(1)前端三大框架
(可以去github查看三个框架的 star星):
vue 尤雨溪,渐进式的JavaScript框架
react Facebook公司,里面的(高阶函数 es6)非常多,对初学者不友好
angular 谷歌公司,目前更新到6.0,学习angular得需要玩一下typescript
(2)cdn方式引用
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.17/dist/vue.js"></script>
(3)下载到本地引用
<script src='./vue.js'></script>
(4)库和框架
上面vue.js文件是一个库,小而精;
框架是功能比较齐全,像Django,大而全,功能比较多;
(5)实例化对象
示例代码:
<script src="./vue.js"></script> <script> // 实例化对象 new Vue({ el:"#app", // 这里data是一个对象,在后续学习中发现data中一般是一个函数 data:{ // 数据属性 msg1:"黄瓜", person:{ name:"alex" }, msg2:'hello Vue', isShow:'True' }, methods:{ // 该组件中声明的方法 }, watch:{ // 该组件中监听的数据属性 } }); </script>
注意:如果是我们自己定义的属性和方法,则全部暴露在外面,如果是vue实例对象自己属性和方法,会在前边加一个”$”进行区分。另外,data中有一个观察者Observer,在观察着一些数据是否发生了改变,若改变,则将改变后的值立马渲染到DOM中对应的地方,控制台查看data效果如下图:
2、vue的模板语法
<div id="app"> <!--模板语法--> <h2>{{ msg1 }}</h2> <h3>{{ 'haha' }}</h3> <h3>{{ 1+1 }}</h3> <h4>{{ {'name':'alex'} }}</h4> <h5>{{ person.name }}</h5> <h2>{{ 1>2?'真的':'假的' }}</h2> <p>{{ msg2.split('').reverse().join('') }}</p> </div>
3、vue的思想:
数据驱动视图,设计模式MVVM(model view viewmodel)
4、vue的基本指令
(使用指令系统后边一定是字符串,且字符串中的变量一定是数据属性中已有的变量)
(1)vue的指令系统之v-text和v-html(***),如下:
<div id="content"> {{ msg }} <div v-text="msg"></div> <!-- v-text相当于innerText --> <div v-html="msg"></div> <!-- v-html相当于innerHTML --> </div> <script src="./vue.js"></script> <script> // 实例化对象 new Vue({ el:"#content", // data中是一个函数 函数中return一个对象,可以是空对象,但不能不return data(){ // 函数的单体模式 return{ msg:"<h2>alex</h2>" } } }); </script>
效果如下图:
(2)条件渲染v-if和v-show,如下:效果如下图:
<div class="box1" v-show="isShow">hello</div> <div class="box2" v-if="isShow">hello</div>
分析:isShow为真则显示div,为假则不显示;
区别:v-show为假时相当于display:none;v-if为假时相当于移除该div,但是有一个占位的注释”<!-- -->”;
官网对v-if和v-show的区别:
1)v-if 是“真正”的条件渲染,因为它会确保在切换过程中条件块内的事件监听器和子组件适当地被销毁和重建。
2)v-if 也是惰性的:如果在初始渲染时条件为假,则什么也不做——直到条件第一次变为真时,才会开始渲染条件块。
3)相比之下,v-show 就简单得多——不管初始条件是什么,元素总是会被渲染,并且只是简单地基于 CSS 进行切换。
4)一般来说,v-if 有更高的切换开销,而 v-show 有更高的初始渲染开销。因此,如果需要非常频繁地切换,则使用 v-show 较好;如果在运行时条件很少改变,则使用 v-if 较好。
v-if与v-else:可以使用 v-else 指令来表示 v-if 的“else 块”:
<div v-if="Math.random() > 0.5"> Now you see me </div> <div v-else> Now you don't </div> // 注意:v-else 元素必须紧跟在带 v-if 或者 v-else-if 的元素的后面,否则它将不会被识别。
(3)v-bind和v-on
v-bind:标签中所有属性,如img标签的src alt,a标签的href title id class等,如下:
<img v-bind:src="imgSrc" v-bind:alt="msg">
v-bind:class='{active:isActive}'表示若isActive(数据属性中定义的变量)为真,则对应div增加active类,否则不增加,如下:
<div class="box" v-bind:class='{active:isActive}'></div>
v-on:监听js中的所有事件,如click,mouseover,mouseout等,如下:
<button v-on:click="clickHandler">切换颜色</button>
v-bind的简便写法是":",如:<div class="box" :class='{active:isActive}'></div>
v-on的简便写法是"@",如:<button @click="clickHandler">切换颜色</button>
(4)列表渲染v-for(不仅可以遍历数组,还可以遍历对象),如下:
<div id="app"> <ul v-if="res.status === 'ok'"> <!-- v-for的优先级是最高的 diff算法 --> <li v-for='(item,index) in res.users' :key="item.id"> <h3>{{ item.id }} -- {{ item.name }} -- {{ item.age }}</h3> </li> </ul> <div v-for='(value,key) in person'> {{ key }}-----{{ value }} </div> </div> <script src="./vue.js"></script> <script> new Vue({ el:"#app", data(){ return { res: { status: 'ok', users: [ {id: 1, name: 'alex', age: 18}, {id: 2, name: 'wusir', age: 30}, {id: 3, name: 'yuan', age: 48} ] }, person: { name: 'tom' } } }, methods:{ // 该组件中声明的方法 }, watch:{ // 该组件中监听的数据属性 } }); </script>
总结:遍历数组时,一个参数是值,两个参数是(值,索引);遍历对象时,一个参数是值,两个参数是(值,键)。
注意:一定要绑定一个标识(有id就绑定id,没有id绑定index),则值改变会直接通过key查找,而不用再去遍历查找,提升效率。
三、Vue应用示例
1、实现轮播图,代码如下:
<div id="app"> <img :src="images[currentIndex].imgSrc" @click="imgHandler" alt=""> <br /> <button @click="prevHandler">上一张</button> <button @click="nextHandler">下一张</button> </div> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> <script> // Vue实例对象,可以有返回值vm,官网中就是用vm代表Vue实例对象 let vm = new Vue({ el: '#app', data() { return { // 实际项目中images这个数据以及图片是后端返回过来的 images:[ {id:1, imgSrc:'./images/1.jpg'}, {id:2, imgSrc:'./images/2.jpg'}, {id:3, imgSrc:'./images/3.jpg'}, {id:4, imgSrc:'./images/4.jpg'} ], currentIndex:0 } }, methods:{ nextHandler(){ this.currentIndex++; if(this.currentIndex == 4){ this.currentIndex = 0; } }, prevHandler(){ this.currentIndex--; if(this.currentIndex == -1){ this.currentIndex = 3; } }, imgHandler(e){ console.log(e); // e是当前事件对象 console.log(e.target); // 当前事件对象的目标对象 console.log(this); // this指当前Vue实例对象 } }, // 组件创建完成时调用created函数,可发送ajax created(){ // 注意:开定时器就要清定时器,后面会介绍在destroyed函数中清掉 setInterval(()=>{ // 定时器中若不用箭头函数则this指则定时器对象 console.log(this); // 这时this指当前Vue实例对象 this.currentIndex++; if(this.currentIndex == 4){ this.currentIndex = 0; } },2000); // 若定时器中不用箭头函数,也可以用下面方式 let _this = this; setInterval(function () { console.log(_this); // _this指当前Vue实例对象 },2000) } }) </script> 示例代码
2、Vue中使用ajax(created是组件创建完成时执行),代码如下:
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <title>Title</title> <meta name="viewport" content="width=device-width, initial-scale=1"> <style> span.active{color:red} </style> </head> <body> <div id="app"> <span @click="clickHandler(index, category.id)" v-for="(category,index) in categoryList" :key="category.id" :class="{active:index==currentIndex}"> {{ category.name }} </span> </div> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> <script src="jquery.min.js"></script> <script> let vm = new Vue({ el: '#app', data() { return { categoryList:[], currentIndex:0 } }, methods:{ clickHandler(i, id){ this.currentIndex = i; // 发起请求 $.ajax({ url:`https://www.luffycity.com/api/v1/courses/?sub_category=${id}`, type:'get', success:function (res) { console.log(res); } }) } }, // 组件创建完成时调用created函数,可发送ajax created(){ $.ajax({ url:'https://www.luffycity.com/api/v1/course_sub/category/list/', type:'get', success:(res) => { // 若不用箭头函数,则this指当前ajax对象 console.log(res); // res是请求接口收到的数据 // 根据响应数据的状态字段判断是否成功 if(res.error_no === 0){ var data = res.data; this.categoryList = data; // this指当前Vue实例对象 let obj = { id:0, name:'全部', category:0 }; // unshift方法表示在数组前插入一个元素 this.categoryList.unshift(obj) } }, error:function (err) { console.log(err); } }) } }) </script> </body> </html> 示例代码
页面运行效果如下图:
依次点击每一项,控制台效果如下图:
3、实现音乐播放器,代码如下:
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <title>Title</title> <meta name="viewport" content="width=device-width, initial-scale=1"> <style> .active{color:blue} </style> </head> <body> <div id="music"> <!-- audio 是HTML5的新标签 --> <!-- @ended 播放完成会自动调用该方法 --> <audio @ended="nextHandler" :src="musicList[currentIndex].songSrc" controls autoplay></audio> <ul> <li @click="songHandler(index)" v-for="(item,index) in musicList" :key="item.id" :class="{active:index==currentIndex}"> <h5>歌名:{{ item.name}}</h5> <p>歌手:{{ item.author}}</p> </li> </ul> </div> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> <script> let musicList = [ { id:1, name:'于荣光 - 少林英雄', author:'于荣光', songSrc:'./static/于荣光 - 少林英雄.mp3' }, { id:2, name:'Joel Adams - Please Dont Go', author:'Joel Adams', songSrc:'./static/Joel Adams - Please Dont Go.mp3' }, { id:3, name:'MKJ - Time', author:'MKJ', songSrc:'./static/MKJ - Time.mp3' }, { id:4, name:'Russ - Psycho (Pt. 2)', author:'Russ', songSrc:'./static/Russ - Psycho (Pt. 2).mp3' } ]; new Vue({ el: '#music', data() { return { musicList:[], currentIndex:0 } }, methods:{ songHandler(i){ this.currentIndex = i }, nextHandler(){ this.currentIndex++; if(this.currentIndex == 4){ this.currentIndex = 0; } } }, created(){ // 实际项目中往往向后台要数据,赋值给数据属性 this.musicList = musicList } }) </script> </body> </html> 示例代码
四、Vue基础知识
1、计算属性(主要产生缓存的数据属性,防止DOM性能消耗)
模板内的表达式非常便利,但是设计它们的初衷是用于简单运算的。在模板中放入太多的逻辑会让模板过重且难以维护。例如:
<div id="example"> {{ message.split('').reverse().join('') }} </div>
在这个地方,模板不再是简单的声明式逻辑。你必须看一段时间才能意识到,这里是想要显示变量message 的翻转字符串。当你想要在模板中多次引用此处的翻转字符串时,就会更加难以处理。所以,对于任何复杂逻辑,你都应当使用计算属性。例如:
<div id="example"> <p>原数据: "{{ message }}"</p> <p>翻转后的数据: "{{ reversedMessage }}"</p> </div> var vm = new Vue({ el: '#example', data: { message: 'Hello' }, computed: { // 计算属性的 getter(计算属性默认只有getter方法),计算属性要有返回值 reversedMessage: function () { return this.message.split('').reverse().join('') // `this`指向vm实例 } } })
2、侦听器(watch)
虽然计算属性在大多数情况下更合适,但有时也需要一个自定义的侦听器。这就是为什么 Vue 通过 watch 选项提供了一个更通用的方法,来响应数据的变化。当需要在数据变化时执行异步或开销较大的操作时,这个方式是最有用的。
watch可以监听单个属性,如果想监听多个属性,则声明多个属性的监听,如下:
<div id="app"> <p>{{ msg }}</p> <button @click='clickHandler'>修改</button> </div> <script src="vue.js"></script> <script> new Vue({ el:'#app', data(){ return { msg:"alex", age:18 } }, methods:{ clickHandler(){ this.msg = "wusir" } }, watch:{ // 监听属性'msg' 'msg':function (value) { console.log(value); if (value === 'wusir'){ this.msg = '大武sir'; } }, // 监听属性'age' 'age':function (value) { } } }) </script>
注意:计算属性即可以监听单个属性,又可以监听多个属性,如下示例:
<div id="app"> <p>{{ myMsg }}</p> <button @click='clickHandler'>修改</button> </div> <script src="vue.js"></script> <script> new Vue({ el:'#app', data(){ return { msg:"alex", age:18 } }, methods:{ clickHandler(){ this.msg = "wusir"; this.age = 20; } }, computed:{ myMsg: function () { // 即监听msg属性,又监听age属性 return `我的名字叫${this.msg},年龄是${this.age}`; } } }) </script>
3、计算属性的应用(上例中音乐播放器改为计算属性实现)
修改audio标签的src属性值,如下:
computed:{ currentSong(){ // 既监听了musicList,又监听了currentIndex return this.musicList[this.currentIndex].songSrc } }
总结:计算属性的方法即可以在模板语法中使用,又可以在指令系统中使用。
4、关于函数中this指向的问题
Vue实例对象中,一般methods和computed中定义的函数中的this是指当前Vue实例对象,而created中的ajax和定时器中定义的函数中的this是指ajax或者定时器对象,这时,ajax和定时器中的函数改为箭头函数,就可以改变this的指向,即this指向当前Vue实例对象。
五、补充知识点
1、查看接口,如下图:
2、json在线格式化工具:
3、自己查阅资料了解js中闭包。