00、ES6的补充(后面用到)
a、let/var
- ES5中的var是没有块级作用域的(if/for)
- ES6中的let是有块级作用域的(if/for)
ES5之前因为if和for都没有块级作用域的概念, 所以在很多时候, 我们都必须借助于function的作用域来解决应用外面变量的问题.(因为function有作用域)
ES6中,加入了let, let它是有if和for的块级作用域
//1.变量作用域: 变量在什么范围内是可用的
{
var name = 'why';
console.log(name);
}
//在括号外面依然可以用,因为ES5之前var是没有块级作用域的概念的
console.log(name);
<button>按钮1</button>
<button>按钮2</button>
<button>按钮3</button>
<button>按钮4</button>
<button>按钮5</button>
<script>
// 没有块级作用域引起的问题: for的块级
var btns = document.getElementsByTagName('button');
for (var i=0; i<btns.length; i++) {
console.log('执行成功');
btns[i].addEventListener('click', function () {
console.log('第' + i + '个按钮被点击');
})
</script>
上面也就相当于执行五次循环,每次循环都是下面这段代码
var i = 5;
var btns = document.getElementsByTagName('button');
btns[i].addEventListener('click', function () {
console.log('第' + i + '个按钮被点击');
})
btns[i].addEventListener('click', function () {
console.log('第' + i + '个按钮被点击');
})
...*3
一、解决作用域问题(ES5)
若要解决此问题,ES5之前可以使用闭包
<button>按钮1</button>
<button>按钮2</button>
<button>按钮3</button>
<button>按钮4</button>
<button>按钮5</button>
<script>
// 为什么闭包可以解决问题: 函数是一个作用域.
var btns = document.getElementsByTagName('button');
for (var i=0; i<btns.length; i++) {
(function (num) {
console.log('执行成功');
btns[i].addEventListener('click', function () {
console.log('第' + num + '个按钮被点击');
})
})(i)
}
</script>
上面就相当于执行五次循环,每次循环的num值都不一样。
二、解决作用域问题(ES6)
如果使用ES6语法的话,就简单很多
let关键字是有块级作用域的概念的
<button>按钮1</button>
<button>按钮2</button>
<button>按钮3</button>
<button>按钮4</button>
<button>按钮5</button>
<script>
const btns = document.getElementsByTagName('button')
for (let i = 0; i < btns.length; i++) {
btns[i].addEventListener('click', function () {
console.log('第' + i + '个按钮被点击');
})
</script>
b、const的使用
const关键字,在很多语言中已经存在, 比如C/C++中, 主要的作用是将某个变量修饰为常量.
在JavaScript中也是如此, 使用const修饰的标识符为常量, 不可以再次赋值.
建议: 在ES6开发中,优先使用const, 只有需要改变某一个标识符的时候才使用let.
<script>
/*
//1.注意一: 一旦给const修饰的标识符被赋值之后, 不能修改
const name = 'why';
//错误,不能修改
name = 'abc';
*/
// 2.注意二: 在使用const定义标识符,必须进行赋值
// const name;
// 3.注意三: 常量的含义是指向的对象不能修改, 但是可以改变对象内部的属性.
const obj = {
name: 'why',
age: 18,
height: 1.88
}
//这样是错误的: obj = {}
console.log(obj);
obj.name = 'kobe';
obj.age = 40;
obj.height = 1.87;
console.log(obj);
</script>
c、对象增强语法
d、高阶函数
高阶函数2.js
let total = nums.filter(n => n<100).map(n => n*2).reduce((pre,n) => pre + n)
<div id="app">
</div>
<script src="../js/vue.js"></script>
<script src="高阶函数2.js"></script>
<script>
console.log(total)
</script>
按照我们之前的方式
高阶函数.js:
const nums = [10, 20, 111, 222, 444, 40, 50]
// 1.需求: 取出所有小于100的数字
let newNums = []
for (let n of nums) {
if (n < 100) {
newNums.push(n)
}
}
// 2.需求:将所有小于100的数字进行转化: 全部*2
let new2Nums = []
for (let n of newNums) {
new2Nums.push(n * 2)
}
// 3.需求:将所有new2Nums数字相加,得到最终的结果
let total = 0
for (let n of new2Nums) {
total += n
}
console.log(total);
利用函数:
const nums = [10, 20, 111, 222, 444, 40, 50]
//1.filter函数的使用
// 10, 20, 40, 50
let newNums = nums.filter(function (n) {
return n < 100
})
//filter函数返回一个数组,将 n<100 的值都存入数组中
// console.log(newNums);
// 2.map函数的使用
// 20, 40, 80, 100
let new2Nums = newNums.map(function (n) { // 20
return n * 2
})
// 3.reduce函数的使用
// reduce作用对数组中所有的内容进行汇总,第一个参数中的第一个值preValue的默认值是第二个参数的值0,第一个参数的第二个值n是
//数组中的值
let total = new2Nums.reduce(function (preValue, n) {
return preValue + n
}, 0)
console.log(total);
//第一次: preValue 0 n 20
//第二次: preValue 20 n 40
//第三次: preValue 60 n 80
//第四次: preValue 140 n 100
//240
转换为高阶函数:
let total = nums.filter(function (n) {
return n < 100
}).map(function (n) {
return n * 2
}).reduce(function (prevValue, n) {
return prevValue + n
}, 0)
console.log(total);
ES6允许使用“箭头”(=>)定义函数
var f = a = > a
//等同于
var f = function(a){
return a;
}
如果箭头函数不需要参数或需要多个参数,就使用一个圆括号代表参数部分。
//无形参
var f = () => 5;
// 等同于
var f = function () { return 5 };
//多个形参
var sum = (num1, num2) => num1 + num2;
// 等同于
var sum = function(num1, num2) {
return num1 + num2;
};
利用箭头函数的高阶函数:
即开头的高阶函数2.js
let total = nums.filter(n => n<100).map(n => n*2).reduce((pre,n) => pre + n)
01、认识和安装Vuejs
a、Vuejs简单介绍
Vue (读音 /vjuː/,类似于 view),不要读错。
Vue是一个渐进式的框架,什么是渐进式的呢?
- 渐进式意味着你可以将Vue作为你应用的一部分嵌入其中,带来更丰富的交互体验。
- 或者如果你希望将更多的业务逻辑使用Vue实现,那么可以使用Vue的核心库以及其生态系统。
- 比如Core+Vue-router+Vuex,也可以满足你各种各样的需求。
Vue有很多特点和Web开发中常见的高级功能
- 解耦视图和数据
- 可复用的组件
- 前端路由技术
- 状态管理
- 虚拟DOM
b、Vuejs安装
安装Vue的方式有很多:
-
方式一:直接CDN引入
你可以选择引入开发环境版本还是生产环境版本
<!-- 开发环境版本,包含了有帮助的命令行警告 --> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> <!-- 生产环境版本,优化了尺寸和速度 --> <script src="https://cdn.jsdelivr.net/npm/vue"></script>
-
方式二:下载和引入
开发环境 https://vuejs.org/js/vue.js 生产环境 https://vuejs.org/js/vue.min.js
-
方式三:NPM安装
后续通过webpack和CLI的使用,我们使用该方式。
02、Vuejs初体验
a、HelloVue代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">{{message}}</div> <!--显示下方数据-->
<div>{{message}}</div> <!--显示{{message}}-->
<script src="../js/vue.js"></script>
<script>
//let(变量)/const(常量)
//let可以再赋值,const定义后不可以再赋值
//在es6里面基本上不用var了,var没有变量作用域的概念,有缺陷。
const app = new Vue({
el:'#app', //用于挂载要管理的元素
data:{ //定义一些数据
message:'你好啊,李银河'
}
})
</script>
</body>
</html>
1、代码做了什么事?
我们来阅读JavaScript代码,会发现创建了一个Vue对象。
创建Vue对象的时候,传入了一些options:{}
{}中包含了el属性:该属性决定了这个Vue对象挂载到哪一个元素上,很明显,我们这里是挂载到了id为app的元素上
{}中包含了data属性:该属性中通常会存储一些数据
这些数据可以是我们直接定义出来的,比如像上面这样,也可能是来自网络,从服务器加载的。
2、浏览器执行代码的流程:
执行到8~9行代码显然出对应的HTML
执行第16行代码创建Vue实例,并且对原HTML进行解析和修改。
并且,目前我们的代码是可以做到响应式的。
b、vue列表展示
<body>
<div id="app">
{{movies}}
</div>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el:'#app',
data:{
movies:['星际穿越','少年派','大话西游']
}
})
</script>
</body>
这样是显示不出来列表的,网页显示是这样:
可以利用v-for显示(后面会讲)
<body>
<div id="app">
<ul>
<li v-for="item in movies ">
{{item}}
</li>
</ul>
</div>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el:'#app',
data:{
movies:['星际穿越','少年派','大话西游']
}
})
</script>
</body>
在浏览器控制台添加列表数据
c、小案例:计数器
点击 + 计数器+1
点击 - 计数器 -1
这里,我们又要使用新的指令和属性了
新的属性:methods,该属性用于在Vue对象中定义方法。
新的指令:@click, 该指令用于监听某个元素的点击事件,并且需要指定当发生点击时,执行的方法(方法通常是methods中定义的方法)
@click 是v-on:click 的语法糖,即 v-on:click的简写。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<h2>当前计数:{{counter}}</h2>
<!--
<button v-on:click="add">+</button>
<button v-on:click="sub">-</button>
-->
<button @click="add">+</button>
<button @click="sub">-</button>
</div>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el:'#app',
data:{
counter:0
},
methods:{
/* add:function (){
console.log('add被执行');
this.counter++;
},
sub:function (){
console.log('sub被执行');
this.counter--;
}*/
add(){
console.log('add被执行');
this.counter++;
},
sub(){
console.log('sub被执行');
this.counter--;
}
}
})
</script>
</body>
</html>
03、Vue的MVVM
MVVM与MVC最大的区别就是:它实现了View和Model的自动同步,也就是当Model的属性改变时,我们不用再自己手动操作Dom元素,来改变View的显示,而是改变属性后该属性对应View层显示会自动改变。
Vue实例中的data相当于Model层,而ViewModel层的核心是Vue中的双向数据绑定,即Model变化时VIew可以实时更新,View变化也能让Model发生变化。
整体看来,MVVM比MVC精简很多,不仅简化了业务与界面的依赖,还解决了数据频繁更新的问题,不用再用选择器操作DOM元素。因为在MVVM中,View不知道Model的存在,Model和ViewModel也观察不到View,这种低耦合模式提高代码的可重用性。
-
View层:
视图层
在我们前端开发中,通常就是DOM层。
主要的作用是给用户展示各种信息。 -
Model层:
数据层
数据可能是我们固定的死数据,更多的是来自我们服务器,从网络上请求下来的数据。
在我们计数器的案例中,就是后面抽取出来的obj,当然,里面的数据可能没有这么简单。 -
VueModel层:
视图模型层
视图模型层是View和Model沟通的桥梁。
一方面它实现了Data Binding,也就是数据绑定,将Model的改变实时的反应到View中
另一方面它实现了DOM Listener,也就是DOM监听,当DOM发生一些事件(点击、滚动、touch等)时,可以监听到,并在需要的情 况下改变对应的Data。
04、Vue的生命周期
a、什么是生命周期?
简而言之:从生到死的过程,从Vue实例创建-运行-销毁的过程
Vue实例有一个完整的生命周期,也就是从开始创建、初始化数据、编译模板、挂载Dom、渲染→更新→渲染、销毁等一系列过程
b、生命周期方法?
Vue从生到死的过程中伴随着各种各样的事件,这些事件会自动触发一些方法.这些方法我们统称为生命周期方法
生命周期钩子 = 生命周期函数 = 生命周期事件
一、创建期间生命周期方法
beforeCreate:
created:
beforeMount
mounted
二、运行期间生命周期方法
beforeUpdate
updated
三、销毁期间的生命周期方法
beforeDestroy
destroyed
四、代码解释
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Vue生命周期方法</title>
<!--引入vue框架-->
<script src="js/vue.js"></script>
</head>
<body>
<div id="app">
<p>{{msg}}</p>
</div>
<script>
let vm = new Vue({
el:'#app',
data:{
msg:"IT程序员的日常"
},
methods:{
say:function () {
console.log("IT程序员的日常");
}
},
beforeCreate:function () {
/*执行beforeCreate的时候,表示Vue刚刚出生,还没有任何内容,data/methods都没有初始化*/
//console.log(this.msg);
//this.say();
//console.log(this.say);
},
created:function () {
/*执行created的时候,表示Vue实例已经初始化好了部分内容,data/methods
想在Vue实例中最早访问到data/methods,只有在这个方法才能访问
*/
//console.log(this.msg);
//this.say();
//console.log(this.say);
},
beforeMount:function () {
/*执行beforeMount,表示已经根据数据编译好了模板,但是还没有渲染到界面上*/
// console.log(document.querySelector("p").innerText);
// console.log(document.querySelector("p").innerHTML);
},
mounted:function () {
/*执行mounted,表示已经根据数据编译好了模板,已经将模板有渲染到界面上,此时可以对界面进行其他操作了*/
console.log(document.querySelector("p").innerText);
console.log(document.querySelector("p").innerHTML);
},
beforeUpdate:function(){
/*主要data中的数据发生了变化就会执行
执行beforeUpdate时候,data的数据已经是最新的了,但是没有更新界面上的数据*/
// console.log(this.msg);
// console.log(document.querySelector("p").innerText);
// console.log(document.querySelector("p").innerHTML);
},
updated:function () {
/*主要data中的数据发生了变化就会执行
执行updated时候,data的数据已经是最新的了,界面上的数据也已经更新*/
/*
console.log(this.msg);
console.log(document.querySelector("p").innerText);
console.log(document.querySelector("p").innerHTML);
*/
},
beforeDestroy:function(){
/*执行beforeDestroy的时候,表示Vue实例即将销毁,但是还未销毁,实例中的数据等都可以使用
最后能使用Vue实例的地址
*/
},
destroyed:function () {
/*
执行destroyed的时候,表示vue实例完全销毁,实例中的任何内容都不能被使用了
*/
}
})
</script>
</body>
</html>
05、模板语法
a、插值操作
一、Mustache
Mustache语法:也就是双大括号语法。
Mustache:胡子/胡须
<div id="app">
<h2>{{message}}</h2>
<h2>{{message}}, 李银河!</h2>
<!--mustache语法中,不仅仅可以直接写变量,也可以写简单的表达式-->
<h2>{{firstName + lastName}}</h2>
<h2>{{firstName + ' ' + lastName}}</h2>
<h2>{{firstName}} {{lastName}}</h2>
<h2>{{counter * 2}}</h2>
</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
当我们不希望界面某些数据跟随改变的时候,可以使用 v-once 指令
该指令后面不需要跟任何表达式(比如之前的v-for后面是由跟表达式的)
该指令表示元素和组件(组件后面才会学习)只渲染一次,不会随着数据的改变而改变
<div id="app">
<h2>{{message}}</h2>
<h2 v-once>{{message}}</h2>
</div>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
message: '你好啊'
}
})
</script>
若利用响应式修改数据:message改变,添加 v-once 的标签所显示的界面没有被重新渲染
三、v-html
某些情况下,我们从服务器请求到的数据本身就是一个HTML代码
如果我们直接通过 {{}} 来输出,会将HTML代码也一起输出。但是我们可能希望的是按照HTML格式进行解析,并且显示对应的内容。
如果我们希望解析出HTML展示,可以使用v-html指令,该指令后面往往会跟上一个string类型,会将字符串中的html解析出来并且进行渲染
<div id="app">
<h2>{{url}}</h2>
<h2 v-html="url"></h2>
</div>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
message: '你好啊',
url: '<a href="http://www.baidu.com">百度一下</a>'
}
})
</script>
四、v-test
v-text作用和Mustache比较相似:都是用于将数据显示在界面中
v-text通常情况下,接受一个string类型
<div id="app">
<h2>{{message}}, 李银河!</h2>
<h2 v-text="message">, 李银河!</h2>
</div>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
message: '你好啊'
}
})
</script>
五、v-pre
v-pre用于跳过这个元素和它子元素的编译过程,用于显示原本的Mustache语法
比如下面的代码:
第一个h2元素中的内容会被编译解析出来对应的内容
第二个h2元素中会直接显示{{message}}
<div id="app">
<h2>{{message}}</h2>
<h2 v-pre>{{message}}</h2>
</div>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
message: '你好啊'
}
})
</script>
六、v-cloak
在某些情况下,我们浏览器可能会直接显然出未编译的Mustache标签
v-cloak指令:它会在vue实例结束编译时从绑定的html元素上移除
cloak: 斗篷
这个指令保持在元素上直到关联实例结束编译。和 CSS 规则如 [v-cloak] { display: none }
一起用时,这个指令可以隐藏未编译的 Mustache 标签直到实例准备完毕。
当网络较慢,网页还在加载 Vue.js ,而导致 Vue 来不及渲染,这时页面就会显示出 Vue 源代码。我们可以使用 v-cloak 指令来解决这一问题。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
[v-cloak] {
display: none;
}
</style>
</head>
<body>
<!--vue解析之前,div中有 v-cloak属性,此标签被隐藏-->
<!--vue解析之后,div中没有 v-cloak属性了,此标签显示-->
<div id="app" v-cloak>
<h2>{{message}}</h2>
</div>
<script src="../js/vue.js"></script>
<script>
setTimeout(function () {
const app = new Vue({
el: '#app',
data: {
message: '你好啊'
}
})
}, 1000)
</script>
</body>
</html>
b、动态绑定属性
前面我们学习的指令主要作用是将值插入到我们模板的内容当中。
但是,除了内容需要动态来决定外,某些属性我们也希望动态来绑定。
比如动态绑定a元素的href属性,比如动态绑定img元素的src属性
这个时候,我们可以使用v-bind指令:
-
作用:动态绑定属性
-
缩写(语法糖)::
一、v-bind的基本使用
<div id="app">
<!-- 错误的做法: 这里不可以使用mustache语法-->
<!--<img src="{{imgURL}}" alt="">-->
<!-- 正确的做法: 使用v-bind指令 -->
<!--alt属性是在图片不能正常加载时候显示的提示语-->
<img v-bind:src="imgURL" alt="">
<a v-bind:href="aHref">百度一下</a>
<!--<h2>{{}}</h2>-->
<!--语法糖的写法-->
<img :src="imgURL" alt="">
<a :href="aHref">百度一下</a>
</div>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
message: '你好啊',
imgURL: 'https://img11.360buyimg.com/mobilecms/s350x250_jfs/t1/20559/1/1424/73138/5c125595E3cbaa3c8/74fc2f84e53a9c23.jpg!q90!cc_350x250.webp',
aHref: 'http://www.baidu.com'
}
})
</script>
二、v-bind动态绑定class
很多时候,我们希望动态的来切换class,比如:
当数据为某个状态时,字体显示红色。当数据另一个状态时,字体显示黑色。
绑定class有两种方式:
- 对象语法
- 数组语法
1、对象语法
对象语法的含义是:class后面跟的是一个对象
对象语法有下面这些用法:
用法一:直接通过{}绑定一个类
<h2 :class="{'active': isActive}">Hello World</h2>
用法二:也可以通过判断,传入多个值
<h2 :class="{'active': isActive, 'line': isLine}">Hello World</h2>
用法三:和普通的类同时存在,并不冲突
注:如果isActive和isLine都为true,那么会有title active line三个类
<h2 class="title" :class="{'active': isActive, 'line': isLine}">Hello World</h2>
用法四:如果过于复杂,可以放在一个methods或者computed中
注:classes是一个计算属性
<h2 class="title" :class="classes">Hello World</h2>
案例:
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
.active {
color: red;
}
</style>
</head>
<body>
<div id="app">
<h2 class="active">{{message}}</h2>
<h2 :class="active">{{message}}</h2>
<!--<h2 v-bind:class="{key1: value1, key2: value2}">{{message}}</h2>-->
<!--<h2 v-bind:class="{类名1: true, 类名2: boolean}">{{message}}</h2>-->
<h2 class="title" v-bind:class="{active: isActive, line: isLine}">{{message}}</h2>
<h2 class="title" v-bind:class="getClasses()">{{message}}</h2>
<button v-on:click="btnClick">按钮</button>
</div>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
message: '你好啊',
isActive: true,
isLine: true
},
methods: {
btnClick: function () {
this.isActive = !this.isActive
},
getClasses: function () {
return {active: this.isActive, line: this.isLine}
}
}
})
</script>
</body>
点击按钮之后:
2、数组语法
数组语法的含义是:class后面跟的是一个数组
数组语法有下面这些用法:
加单引号表示字符串,没有单引号表示变量
用法一:直接通过[]绑定一个类
<h2 :class="['active']">Hello World</h2>
用法二:也可以传入多个值
<h2 :class="['active', 'line']">Hello World</h2>
用法三:和普通的类同时存在,并不冲突
注:会有title/active/line三个类
<h2 class="title" :class="['active', 'line']">Hello World</h2>
用法四:如果过于复杂,可以放在一个methods或者computed中
注:classes是一个计算属性
<h2 class="title" :class="classes">Hello World</h2>
案例:
<div id="app">
<!--加上' ' 表示字符串-->
<h2 class="title" :class="['active', 'line']">{{message}}</h2>
<!--不加' ' 表示变量-->
<h2 class="title" :class="[active, line]">{{message}}</h2>
<h2 class="title" :class="getClasses()">{{message}}</h2>
</div>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
message: '你好啊',
active: 'aaaaaa',
line: 'bbbbbbb'
},
methods: {
getClasses: function () {
return [this.active, this.line]
}
}
})
</script>
三、v-bind和v-for的联合使用
作业需求: 点击列表中的哪一项, 那么该项的文字变成红色
v-for中使用下标属性
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
.active{
color: red;
}
</style>
</head>
<body>
<!--作业需求: 点击列表中的哪一项, 那么该项的文字变成红色-->
<div id="app">
<ul>
<li v-for="(m, index) in movies" :class="{active: isActive == index}" @click="changeColor(index)">{{m}}</li>
</ul>
</div>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
movies: ['海王', '海尔兄弟', '火影忍者', '进击的巨人'],
isActive : -1
},
methods:{
changeColor(index){
this.isActive = index;
}
}
})
</script>
</body>
</html>
四、v-vind动态绑定style
我们可以利用v-bind:style来绑定一些CSS内联样式
在写CSS属性名的时候,比如font-size,我们可以使用驼峰式 (camelCase) fontSize ,或短横线分隔 (kebab-case,记得用单引号括起来) ‘font-size’
绑定class有两种方式:
- 对象语法
- 数组语法
1、对象语法
:style="{color: currentColor, fontSize: fontSize + 'px'}"
style后面跟的是一个对象类型
对象的key是CSS属性名称
对象的value是具体赋的值,值可以来自于data中的属性
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
.title {
font-size: 50px;
color: red;
}
</style>
</head>
<body>
<div id="app">
<!--<h2 :style="{key(属性名): value(属性值)}">{{message}}</h2>-->
<!--'50px'必须加上单引号, 否则是当做一个变量去解析-->
<!--<h2 :style="{fontSize: '50px'}">{{message}}</h2>-->
<!--finalSize当成一个变量使用-->
<!--<h2 :style="{fontSize: finalSize}">{{message}}</h2>-->
<h2 :style="{fontSize: finalSize + 'px', backgroundColor: finalColor}">{{message}}</h2>
<h2 :style="getStyles()">{{message}}</h2>
</div>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
message: '你好啊',
finalSize: 100,
finalColor: 'red',
},
methods: {
getStyles: function () {
return {fontSize: this.finalSize + 'px', backgroundColor: this.finalColor}
}
}
})
</script>
</body>
</html>
2、数组语法
<div v-bind:style="[baseStyles, overridingStyles]"></div>
style后面跟的是一个数组类型
多个值以 , 分割即可
案例:
<div id="app">
<h2 :style="[baseStyle, baseStyle1]">{{message}}</h2>
</div>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
message: '你好啊',
baseStyle: {backgroundColor: 'red'},
baseStyle1: {fontSize: '100px'},
}
})
</script>
c、计算属性
计算属性是写在实例的computed选项中的
一、计算属性的基本使用
<div id="app">
<h2>{{firstName + ' ' + lastName}}</h2>
<h2>{{firstName}} {{lastName}}</h2>
<h2>{{getFullName()}}</h2>
<!--计算属性不用加(),将其当做一个属性使用-->
<h2>{{fullName}}</h2>
</div>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
firstName: 'Lebron',
lastName: 'James'
},
// computed: 计算属性()
computed: {
fullName: function () {
return this.firstName + ' ' + this.lastName
}
},
methods: {
getFullName() {
return this.firstName + ' ' + this.lastName
}
}
})
</script>
二、计算属性的复杂操作
<div id="app">
<h2>总价格: {{totalPrice}}</h2>
</div>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
books: [
{id: 110, name: 'Unix编程艺术', price: 119},
{id: 111, name: '代码大全', price: 105},
{id: 112, name: '深入理解计算机原理', price: 98},
{id: 113, name: '现代操作系统', price: 87},
]
},
computed: {
totalPrice: function () {
let result = 0
for (let i = 0; i < this.books.length; i++) {
result += this.books[i].price
}
return result
/*其他循环的写法*/
/*for (let i in this.books) {
result += this.books[i].price
}*/
/* for (let book of this.books) {
result +=book.price
}*/
}
}
})
</script>
三、计算属性的getter和setter
上面写的计算属性只是简写,实际上是利用get方法
<div id="app">
<h2>{{fullName}}</h2>
</div>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
firstName: 'Kobe',
lastName: 'Bryant'
},
computed: {
/* fullName: function () {
return this.firstName + ' ' + this.lastName
}*/
//上面是计算属性的简写,实际上计算属性是这样写的
// 计算属性一般是没有set方法, 只读属性.
fullName: {
//若使用set方法,需要接受参数
set: function(newValue) {
// console.log('-----', newValue);
//利用空格分隔符,将firstName和lastName分出
const names = newValue.split(' ');
this.firstName = names[0];
this.lastName = names[1];
},
get: function () {
return this.firstName + ' ' + this.lastName
}
},
}
})
</script>
四、计算属性和methods的对比
计算属性有缓存
<div id="app">
<!--1.直接拼接: 语法过于繁琐,一般不用-->
<!--<h2>{{firstName}} {{lastName}}</h2>-->
<!--2.通过定义methods-->
<h2>{{getFullName()}}</h2>
<h2>{{getFullName()}}</h2>
<h2>{{getFullName()}}</h2>
<h2>{{getFullName()}}</h2>
<!--3.通过computed-->
<h2>{{fullName}}</h2>
<h2>{{fullName}}</h2>
<h2>{{fullName}}</h2>
<h2>{{fullName}}</h2>
</div>
<script src="../js/vue.js"></script>
<script>
// angular -> google
// TypeScript(microsoft) -> ts(类型检测)
// flow(facebook) ->
const app = new Vue({
el: '#app',
data: {
firstName: 'Kobe',
lastName: 'Bryant'
},
methods: {
getFullName: function () {
console.log('getFullName');
return this.firstName + ' ' + this.lastName
}
},
computed: {
fullName: function () {
console.log('fullName');
return this.firstName + ' ' + this.lastName
}
}
})
</script>
d、事件监听
在前端开发中,我们需要经常和用于交互
这个时候,我们就必须监听用户发生的时间,比如点击、拖拽、键盘事件等等
在Vue中如何监听事件呢?使用v-on指令
一、v-on的基本使用
<div id="app">
<h2>{{counter}}</h2>
<!--可以直接写成表达式-->
<button v-on:click="counter++">+</button>
<button v-on:click="counter--">-</button>
<!--写成函数形式-->
<!--<button v-on:click="increment">+</button>-->
<!--<button v-on:click="decrement">-</button>-->
<!--语法糖格式:@ -->
<button @click="increment">+</button>
<button @click="decrement">-</button>
</div>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
counter: 0
},
methods: {
increment() {
this.counter++
},
decrement() {
this.counter--
}
}
})
</script>
二、v-on的参数问题
<div id="app">
<!--1.事件调用的方法没有参数-->
<button @click="btn1Click()">按钮1</button>
<button @click="btn1Click">按钮1</button>
<!--<button @click="btn2Click(123)">按钮2</button>-->
<!-- 生成的是 -------- 123-->
<!--如果函数需要参数,但是没有传入, 那么函数的形参为undefined-->
<!-- <button @click="btn2Click()">按钮2</button>-->
<!-- 生成的是 -------- undefined-->
<!--2.在事件定义时, 写方法时省略了小括号, 但是方法本身是需要一个参数的,
这个时候, Vue会默认将浏览器生产的event原生事件对象作为参数传入到方法-->
<button @click="btn2Click">按钮2</button>
<!--3.方法定义时, 我们需要event对象, 同时又需要其他参数-->
<!-- 在调用方法时, 如何手动的获取到浏览器参数的event对象: $event-->
<button @click="btn3Click(abc, $event)">按钮3</button>
</div>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
message: '你好啊',
abc: 123
},
methods: {
btn1Click() {
console.log("btn1Click");
},
btn2Click(event) {
console.log('--------', event);
},
btn3Click(abc, event) {
console.log('++++++++', abc, event);
}
}
})
</script>
三、v-on的修饰符
事件冒泡:点击子级元素接收到事件后,会把他接收到的事件传播给他的父级,也就是父级也会接收到子级的事件
<div id="app">
<!--1. .stop修饰符的使用,阻止Html的事件冒泡-->
<!--若不加 .stop修饰符,会发生事件冒泡,即点击div中的按钮,回调bthClick方法,会将接收到的事件传播给他的父级(div),也就是divClick也会被回调-->
<div @click="divClick">
aaaaaaa
<button @click.stop="btnClick">按钮</button>
</div>
<!--2. .prevent修饰符的使用-->
<!--阻止默认行为,点击提交后,不会直接跳转,而会回调submitClick方法-->
<br>
<form action="baidu">
<input type="submit" value="提交" @click.prevent="submitClick">
</form>
<!--3. @keyup. 监听某个键盘的键帽,这是监听回车,当回车敲下并回弹的时候,回调keyup方法-->
<!--若只写 @keyup="keyUp",则点击任意键盘回弹的时候都会回调keyUp方法-->
<input type="text" @keyup.enter="keyUp">
<!--4. .once修饰符的使用-->
<!-- 点击回调只会调用一次,点击第二次的时候不会被调用-->
<button @click.once="btn2Click">按钮2</button>
</div>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
message: '你好啊'
},
methods: {
btnClick() {
console.log("btnClick");
},
divClick() {
console.log("divClick");
},
submitClick() {
console.log('submitClick');
},
keyUp() {
console.log('keyUp');
},
btn2Click() {
console.log('btn2Click');
}
}
})
</script>
e、条件判断
一、v-if的使用
v-if后面的条件为false时,对应的元素以及其子元素不会渲染,也就是根本没有不会有对应的标签出现在DOM中。
<div id="app">
<h2 v-if="isShow">
<div>abc</div>
<div>abc</div>
<div>abc</div>
<div>abc</div>
<div>abc</div>
{{message}}
</h2>
</div>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
message: '你好啊',
isShow: true
}
})
</script>
二、v-if和v-else的使用
<div id="app">
<h2 v-if="isShow">
<div>abc</div>
<div>abc</div>
<div>abc</div>
<div>abc</div>
<div>abc</div>
{{message}}
</h2>
<h1 v-else>isShow为false时, 显示我</h1>
</div>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
message: '你好啊',
isShow: true
}
})
</script>
三、v-if和v-else-if和v-else的使用
一般这种多条件判断不用这些语法,可以封装为计算属性或者函数
<div id="app">
<h2 v-if="score>=90">优秀</h2>
<h2 v-else-if="score>=80">良好</h2>
<h2 v-else-if="score>=60">及格</h2>
<h2 v-else>不及格</h2>
<!--<h1>{{result}}</h1>-->
</div>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
score: 62
},
/*
//一般不用 v-if v-else-if...的语法,因为有些麻烦,一般封装为函数或者计算属性,方便调用
computed: {
result() {
let showMessage = '';
if (this.score >= 90) {
showMessage = '优秀'
} else if (this.score >= 80) {
showMessage = '良好'
}else if (this.score>=60){
showMessage = '及格'
}else {
showMessage = '不及格'
}
return showMessage
}
}*/
})
</script>
四、用户登陆切换的案例
<div id="app">
<span v-if="isUser">
<label for="username">用户账号</label>
<input type="text" id="username" placeholder="用户账号">
</span>
<span v-else>
<label for="email">用户邮箱</label>
<input type="text" id="email" placeholder="用户邮箱">
</span>
<button @click="isUser = !isUser">切换类型</button>
</div>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
isUser: true
}
})
</script>
但是这样会有一个问题,如果我们在有输入内容的情况下,切换了类型,我们会发现文字依然显示之前的输入的内容。
但是按道理讲,我们应该切换到另外一个input元素中了。在另一个input元素中,我们并没有输入内容。
这是因为Vue在进行DOM渲染时,出于性能考虑,会尽可能的复用已经存在的元素,而不是重新创建新的元素。
在上面的案例中,Vue内部会发现原来的input元素不再使用,直接作为else中的input来使用了。
解决方案:
如果我们不希望Vue出现类似重复利用的问题,可以给对应的input添加key
并且我们需要保证key的不同
更改方案:
添加key,保证key的不同
<div id="app">
<span v-if="isUser">
<label for="username">用户账号</label>
<input type="text" id="username" placeholder="用户账号" key="username">
</span>
<span v-else>
<label for="email">用户邮箱</label>
<input type="text" id="email" placeholder="用户邮箱" key="email">
</span>
<button @click="isUser = !isUser">切换类型</button>
</div>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
isUser: true
}
})
</script>
五、v-show的使用
v-show的用法和v-if非常相似,也用于决定一个元素是否渲染:
v-if和v-show都可以决定一个元素是否渲染,那么开发中我们如何选择呢?
-
v-if当条件为false时,压根不会有对应的元素在DOM中。
-
v-show当条件为false时,仅仅是将元素的display属性设置为none而已。
开发中如何选择呢?
- 当需要在显示与隐藏之间切片很频繁时,使用v-show
- 当只有一次切换时,通过使用v-if
<div id="app">
<!--v-if: 当条件为false时, 包含v-if指令的元素, 根本就不会存在dom中-->
<h2 v-if="isShow" id="aaa">{{message}}</h2>
<!--v-show: 当条件为false时, v-show只是给我们的元素添加一个行内样式: display: none-->
<h2 v-show="isShow" id="bbb">{{message}}</h2>
</div>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
message: '你好啊',
isShow: true
}
})
</script>
f、循环遍历
一、v-for循环数组
当我们有一组数据需要进行渲染时,我们就可以使用v-for来完成。
v-for的语法类似于JavaScript中的for循环
格式如下:item in items的形式
<div id="app">
<!--1.在遍历的过程中,没有使用索引值(下标值)-->
<ul>
<li v-for="item in names">{{item}}</li>
</ul>
<!--2.在遍历的过程中, 获取索引值-->
<ul>
<li v-for="(item, index) in names">
{{index+1}}.{{item}}
</li>
</ul>
</div>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
names: ['why', 'kobe', 'james', 'curry']
}
})
</script>
二、v-for遍历对象
<div id="app">
<!--1.在遍历对象的过程中, 如果只是获取一个值, 那么获取到的是value-->
<ul>
<li v-for="item in info">{{item}}</li>
</ul>
<!--2.获取key和value 格式: (value, key) -->
<ul>
<li v-for="(value, key) in info">{{value}}-{{key}}</li>
</ul>
<!--3.获取key和value和index 格式: (value, key, index) -->
<ul>
<li v-for="(value, key, index) in info">{{value}}-{{key}}-{{index}}</li>
</ul>
</div>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
info: {
name: 'why',
age: 18,
height: 1.88
}
}
})
</script>
三、v-for使用过程添加key
官方推荐我们在使用v-for时,给对应的元素或组件添加上一个:key属性
为什么需要这个key属性呢(了解)
这个其实和Vue的虚拟DOM的Diff算法有关系
这里我们借用React’s diff algorithm中的一张图来简单说明一下:
当某一层有很多相同的节点时,也就是列表节点时,我们希望插入一个新的节点,我们希望可以在B和C之间加一个F,Diff算法默认执行起来是这样的:即把C更新成F,D更新成C,E更新成D,最后再插入E,是不是很没有效率
所以我们需要使用key来给每个节点做一个唯一标识
Diff算法就可以正确的识别此节点
找到正确的位置区插入新的节点。
所以一句话,key的作用主要是为了高效的更新虚拟DOM
div id="app">
<ul>
<!--绑定的key必须和后面的item是一一对应的,所以不能用index-->
<li v-for="item in letters" :key="item">{{item}}</li>
</ul>
</div>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
letters: ['A', 'B', 'C', 'D', 'E']
}
})
</script>
四、检测哪些数组方法响应式
为Vue是响应式的,所以当数据发生变化时,Vue会自动检测数据变化,不用刷新页面,视图会发生对应的更新
<div id="app">
<ul>
<li v-for="item in letters">{{item}}</li>
</ul>
<button @click="btnClick">按钮</button>
</div>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
letters: ['a', 'b', 'c', 'd']
},
methods: {
btnClick() {
// 1.push方法 添加最后一个元素
// this.letters.push('aaa')
// this.letters.push('aaaa', 'bbbb', 'cccc')
// 2.pop(): 删除数组中的最后一个元素
// this.letters.pop();
// 3.shift(): 删除数组中的第一个元素
// this.letters.shift();
// 4.unshift(): 在数组最前面添加元素
// this.letters.unshift()
// this.letters.unshift('aaa', 'bbb', 'ccc')
// 5.splice作用: 删除元素/插入元素/替换元素
/*
删除元素: 第二个参数传入你要删除几个元素(如果没有传,就删除后面所有的元素)
替换元素: 第二个参数, 表示我们要替换几个元素, 后面是用于替换前面的元素
插入元素: 第二个参数, 传入0, 并且后面跟上要插入的元素
*/
this.letters.splice(1, 3, 'm', 'n', 'l', 'x')
// this.letters.splice(1, 0, 'x', 'y', 'z')
// 6.sort() 排序
// this.letters.sort()
// 7.reverse() 反转数据
// this.letters.reverse()
// 注意: 通过索引值修改数组中的元素,这个不是响应式的
// this.letters[0] = 'bbbbbb';
//若要修改,则可以通过以下代码修改
//方法1
// this.letters.splice(0, 1, 'bbbbbb')
//方法2
// set(要修改的对象, 索引值, 修改后的值)
// Vue.set(this.letters, 0, 'bbbbbb')
}
}
})
</script>
通过索引值修改数组中的元素,不是响应式的,可以利用splice或者Vue的set方法修改数组中的元素
g、书籍购物车案例
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<!--rel 属性规定当前文档与被链接文档之间的关系。
只有 rel 属性为 "stylesheet" 值得到了所有浏览器的支持。其他值只得到了部分地支持。
-->
<link rel="stylesheet" href="style.css">
</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>
<tbody>
<tr v-for="(item, index) in books">
<td>{{item.id}}</td>
<td>{{item.name}}</td>
<td>{{item.date}}</td>
<!--用 | 符号后跟过滤器,前面加相当于传入的参数-->
<td>{{item.price | showPrice}}</td>
<td>
<!--当书籍的数量小于或等于1的时候,无效化 - 按钮-->
<button @click="decrement(index)" v-bind:disabled="item.count <= 1">-</button>
{{item.count}}
<button @click="increment(index)">+</button>
</td>
<td><button @click="removeHandle(index)">移除</button></td>
</tr>
</tbody>
</table>
<h2>总价格: {{totalPrice | showPrice}}</h2>
</div>
<h2 v-else>购物车为空</h2>
</div>
<script src="../js/vue.js"></script>
<script src="main.js"></script>
<script>
</script>
</body>
</html>
main.js
const app = new Vue({
el: '#app',
data: {
books: [
{
id: 1,
name: '《算法导论》',
date: '2006-9',
price: 85.00,
count: 1
},
{
id: 2,
name: '《UNIX编程艺术》',
date: '2006-2',
price: 59.00,
count: 1
},
{
id: 3,
name: '《编程珠玑》',
date: '2008-10',
price: 39.00,
count: 1
},
{
id: 4,
name: '《代码大全》',
date: '2006-3',
price: 128.00,
count: 1
},
]
},
methods: {
// 可以这样写,也可以加个过滤器
//getFinalPrice(price) {
// return '¥' + price.toFixed(2)
// }
increment(index) {
this.books[index].count++
},
decrement(index) {
this.books[index].count--
},
removeHandle(index) {
this.books.splice(index, 1)
}
},
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
}
},
filters: {
showPrice(price) {
return '¥' + price.toFixed(2)
}
}
})
style.css
table {
/*border:边框的样式 1px表示线的像素 solid表示实线 #e9e9e9表示白色*/
border: 1px solid #e9e9e9;
/*为表格设置合并边框模型
border-collapse 属性设置表格的边框是否被合并为一个单一的边框,还是象在标准的 HTML 中那样分开显示
*/
border-collapse: collapse;
/*设置表格的边框间距*/
border-spacing: 0;
}
th, td {
/*边距填充*/
padding: 8px 16px;
border: 1px solid #e9e9e9;
text-align: left;
}
th {
/*背景颜色*/
background-color: #5c6b77;
/*字体颜色*/
color: #f7f7f7;
/*设置段落字体的粗细*/
font-weight: 600;
}