参考:(不错的一篇笔记)
--- 目录 ---
1. Vue的安装方式
- 直接在官网下载对应的js文件,然后在项目中引入。
- CND引入
- npm安装
2. Vue中的MVVM
3. Vue中的模板语法
- Mustache语法:双大括号
- v-html & v-text
v-html :将字符串按照html格式解析,并显示对应的内容
<h2 v-html="url"></h2> <!-- 链接展示 -->
<h3 v-text="message">,泡泡</h3> <!-- v-text运用不灵活,会把其他内容覆盖 -->
data:{
message:'你好啊',
url:'<a href="http://www.baidu.com">百度一下</a>',
}
- v-pre
<h3 v-pre>{{message}}</h3> <!-- 直接显示,不做解析{{message}} -->
- v-cloak
在vue解析之前,div中有一个属性v-cloak
在vue解析之后,div中没有一个属性v-cloak
<style>
[v-cloak] {
display: none;
}
</style>
<!-- v-cloak了解即可,可以在元素渲染之前,设置元素隐藏,渲染完毕后这个属性消失,元素展示 -->
<div id="app" v-cloak>
{{message}}
</div>
- v-bind
- 作用:动态绑定属性
- 语法糖:直接写一个:
<!-- 只有内容中可以使用mustache语法,不可以直接在标签的属性中加{{}} -->
<img v-bind:src="imgURL" alt=""> <!-- 动态绑定src -->
<a :href="ahref">百度</a>
- 01 动态绑定class语法:
<div id="app">
<!-- 可以通过布尔值动态绑定类名 -->
<!-- <h2 v-bind:class="{类名1:true,类名2:boolean}">{{message}}</h2> -->
<h2 class="title" v-bind:class="{active:isactive,line:isline}">{{message}}</h2> <!-- 对象语法 -->
<!-- 可以写固定class,vue会进行合并 -->
<button v-on:click='btnClick'>按钮</button>
</div>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el:"#app",
data:{
message:'三生三世',
imgURL:'https://www.baidu.com/img/PCtm_d9c8750bed0b3c7d089fa7d55720d6cf.png',
ahref:'http://www.baidu.com',
isactive:true, //可以动态修改布尔值
isline:true
},
methods: {
btnClick:function(){
this.isactive = !this.isactive;
}
}
})
</script>
- 02 绑定数组语法
<div id="app">
<!-- 少用,因为这样相当于类是写死的 -->
<h2 class="title" :class="getClasses()">{{message}}</h2>
</div>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el:'#app',
data:{
message:'哈哈哈',
active:'aaa',
line:'bbb'
},
methods:{
getClasses:function(){
return [this.active,this.line]
}
}
})
</script>
- 03 动态绑定style
- 使用对象绑定
<div id="app">
<!-- <h2 :style="{key(css属性名):boolean}">{message}</h2> -->
<!-- <h2 :style="{fontSize:'50px'}">{{message}}</h2> --> <!-- '50px'加'',否则会被解析成变量 -->
<!-- 当成变量使用 -->
<h2 :style="{fontSize:finalSize+'px',color:finalColor}">{{message}}</h2>
</div>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el:"#app",
data:{
message:'哈哈哈',
// finalSize:'100px',
finalSize:'50', //可以连接px
finalColor:'red',
},
methods:{
}
})
</script>
- 使用数组绑定
<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',color:'green'},
baseStyle1:{ fontSize:'100px'}
},
methods:{
getStyles:function(){
return {fontSize:this.finalSize+'px',color:this.finalColor};
}
}
})
</script>
- 计算属性
- 简单的计算属性操作
<div id="app">
<h2>{{getFullname()}}</h2>
<h2>{{fullName}}</h2> <!-- 不需要加() -->
</div>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el:"#app",
data:{
firstname:'iben',
lastname:'love'
},
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:109},
{id:112,name:'深入理解计算机原理',price:143},
{id:113,name:'操作系统',price:101},
]
},
computed:{
//计算属性
totalPrice:function(){
let result = 0;
for(let i=0;i<this.books.length;i++) {
result = result + this.books[i].price;
}
return result;
/*
es6语法:
for(let i in this.books){
this.books[i];
}
for(let book of this.books){
book
}
*/
}
}
})
</script>
- 计算属性的getter和setter
每一个计算属性都包含一个getter和setter。(setter一般省略)
<div id="app">
<h2>{{fullname}}</h2>
</div>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el:"#app",
data:{
firstname:'dsd',
lastname:'nan',
},
computed:{
//简写
/* fullname:function(){
return this.firstname+' '+this.lastname;
}
*/
//计算属性一般是没有set方法的,只读属性,可省略
fullname:{
set:function(newValue){
const names = newValue.split(' ');
this.firstname = names[0];
this.lastname = names[1];
},
//一般属性只需要设置get方法
get:function(){
return this.firstname+' '+this.lastname;;
}
}
}
})
</script>
- 计算属性和methods的对比
计算属性会进行缓存,如果多次使用时,计算属性只会调用一次。
methods:{ //调用则执行,可执行多次
getFullName:function(){
return this.firstname +' '+ this.lastname;
}
},
computed:{ //只执行一次,计算属性有缓冲,高效
fullname:{
get:function(){
return this.firstname+' '+this.lastname;;
}
}
}
4. ES6知识补充
- ES5中的var是没有块级作用域的,而ES6的let是有块级作用域的。(if / for),js中用var来声明一个变量时,变量的作用域主要是和函数的定义有关,函数有作用域,而对于其他块定义是没有作用域的,let是进行了改进。
<script>
var btns = document.getElementsByTagName('button');
/*
不可以使用var,否则结果错误,当我们可以使用闭包解决,比较麻烦。
for (var i = 0; i < btns.length; i++) {
(function(i){
btns[i].addEventListener('click',function(){
console.log('第'+i+'个按钮被点击');
})
})(i) //定义函数,并立马执行(function(i){...})(i) 函数是有作用域的
}
*/
//es6新特性let --- 有块级作用域
for (let i = 0; i < btns.length; i++) {
btns[i].addEventListener('click',function(){
console.log('第'+i+'个按钮被点击');
})
}
</script>
- const的使用和注意点
使用const修饰的标识符为常量,不可以再次赋值。(建议:在es6开发中,优先使用const,只有需要改变某一个标识符的时候才用let)
//1 一旦给const修饰的标识符赋值之后,不能修改
const name = 'pao';
//name = '22';
//2 在使用const定义标识符时,必须赋值
// const name;
//3 常量的含义是指向的对象(内存地址)不能修改,但是可以修改对象内部的属性
const obj = {
name:'why',
age:18,
height:1.88
}
console.log(obj); //{name: "why", age: 18, height: 1.88}
obj.name = 'cobe';
obj.age = 20;
console.log(obj); //{name: "cobe", age: 20, height: 1.88}
- es6对象字面量的增强写法
const name = 'why';
const age = 18;
const height = '1.88';
//es5写法
/*
const obj = {
name:name,
age:age,
height:height,
run:function(){
}
}
console.log(obj); //{name: "why", age: 18, height: "1.88"}
*/
//es6写法
const obj = {
//变量写法
name,
age,
height,
//2 函数的增强写法
run(){
console.log('跑步');
}
}
console.log(obj); //{name: "why", age: 18, height: "1.88"}
5. 事件
01 v-on 绑定事件监听器(@)
<div id="app">
<h2>{{counter}}</h2>
<button v-on: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>
- 参数传递问题:
事件监听时,如果该方法不需要有额外参数,那么方法后的()可以不添加 (注意:如果方法本身中有一个参数,那么会默认将原生事件的event参数传递进入)
<div id="app">
<!-- 1 事件调用方法没有参数,省略() -->
<button @click="btn1Click">按钮1</button>
<!-- 在事件定义时,写函数时省略了 -->
<button @click="btn2Click(123)">按钮2</button>
<!-- 2 空参undefined :<button @click="btn2Click()">按钮2</button> 带参数必须加()-->
<!-- 3 无传参:MouseEvent{...} vue会将浏览器生成的event事件对象作为参数传入到方法-->
<button @click="btn2Click">按钮3</button>
<!-- 4 方法定义时,我们需要event对象,同时又需要其他参数 -->
<!-- 在调用方法时,如何手动获取浏览器参数的event对象,$event -->
<button @click="btn3Click(123,$event)">按钮4</button>
</div>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el:"#app",
data:{
counter:0
},
methods:{
btn1Click(){
console.log('btn1Click');
},
btn2Click(event){
console.log('-------',event); //MouseEvent {...}
},
btn3Click(abc,event){
console.log('+++++++',abc,event); //123 MouseEvent {...}
},
}
})
//如果函数需要参数,但是没有传入,那么函数的形参为undefined
function abc(name){
console.log(name);
}
abc(); //undefined
</script>
- v-on修饰符的使用
- .stop – 调用event.stopPropagation()阻止事件冒泡
- .prevent – 调用event.preventDefault()阻止默认事件
- @keyup.keyCode | keyAlias :监听键盘键的点击
- .native监听组件根元素的原生事件
- .once只触发一次
<div id="app">
<div @click="divClick">
aa 点击div aaa
<!-- 1 使用.stop修饰符阻止事件冒泡 -->
<button @click.stop="btnClick">按钮</button>
</div>
<br>
<!-- 2 .prevent 阻止默认事件 -->
<form action="baidu">
input type="submit" value="提交" @click.prevent="submitClick">
</form>
<br>
<!-- 3 监听键盘键的点击 -->
<!-- 会监听所有按键,也可以自己指定按键监听 -->
<input type="text" @keyup.enter="KeyUp">
<br>
<!-- 4 .native监听组件根元素的原生事件 -->
<cpn @click.native="cpnclick"></cpn>
<br>
<!-- 5 .once只触发一次 -->
<button @click.once="btn2Click">按钮2</button>
</div>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el:"#app",
data:{
counter:0
},
methods:{
btnClick(){
console.log("btnClick");
},
divClick(){ //事件冒泡,会触发事件
console.log("divClick");
},
submitClick(){
console.log("submitClick");
},
KeyUp(){
console.log("KeyUp");
},
btn2Click(){
console.log("btn2Click");
}
}
})
</script>
02 条件判断
- if / if else
<div id="app">
<!-- 1 v-if -->
<h2 v-if="isShow">
<div>abc</div>
<div>abc</div>
<div>abc</div>
<div>abc</div>
<div>abc</div>
{{message}}
</h2>
<!-- 2 v-if v-else结合使用 -->
<h1 v-else>
isShow为false时显示else
</h1>
</div>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el:"#app",
data:{
message:'哈哈哈',
isShow:true,
score:99
}
})
</script>
- if else-if
<!--3 else if -->
<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:99
},
computed:{
//条件复杂时不建议在标签里判断,可以使用计算属性
result(){
let showMag = '';
if(this.score >= 90){
showMag = '优秀'
}else if(this.score >= 80){
showMag = '良好'
}else {
showMag = '不及格'
}
return showMag;
}
}
})
</script>
登录切换小案例
补充一个虚拟dom复用元素的内容
<div id="app">
<span v-if="isUser">
<label for="username">用户账号</label>
<input type="text" id="username" placeholder="用户账号" key="username">
</span>
<!-- 虚拟dom会对某一些元素复用,导致输入框的内容在切换时不清空,可以
加一个key属性作为标识符区分,这时vue不会复用key不同的元素 -->
<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>
03 v-show和v-if的区别
-
区别:
v-if:当条件为false,包含v-if的元素,根本不存在dom中
v-show: 当条件为false,v-show只是给元素增加了一个行内样式,display:none,其实元素仍存在dom中 -
使用:
1.显示和隐藏切换频率很高时,使用v-show
2.只有一次切换时,使用v-if
<div id="app">
<h2 v-if="isShow" id="aaa">{{message}}</h2>
<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>
04 v-for循环
- 遍历数组:
<div id="app">
<!-- 1 遍历中没有加入下标值 -->
<h2 v-for="item in names">{{item}}</h2>
<!-- 2 遍历过程中获取索引值 -->
<h2 v-for="(item,index) in names">
{{index+1}}.{{item}}
</h2>
</div>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el:"#app",
data:{
names:['why','kone','jane','cutt']
}
})
</script>
- 遍历对象:
<div id="app">
<!-- 获取对象中的值 -->
<ul>
<li>{{info.name}}</li>
<li>{{info.age}}</li>
<li>{{info.height}}</li>
</ul>
<!-- 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>
- for绑定和非绑定key的区别
官方推荐,在使用v-for的时候,给对应的元素或组件加上一个key属性。(key的作用主要是为了高效地更新虚拟dom,key需要保证唯一性)- 为什么需要key属性?
和vue的虚拟dom的diff算法有关,使用key为每个节点做一个唯一标识,diff算法就可以正确地识别节点,找到正确的位置插入新的节点。
- 为什么需要key属性?
<div id="app">
<ul>
<!-- key不要绑定indx,会改变,绑定item可以一一对应 -->
<li v-for="item in letter" :key="item">{{item}}</li>
</ul>
</div>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el:"#app",
data:{
letter:['a','b','c','d','e']
}
})
</script>
- 数组中哪些方法是响应式的
<div id="app">
<ul>
<li v-for="item in letter">{{item}}</li>
</ul>
<button @click="btnClick">按钮</button>
</div>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el:"#app",
data:{
letter:['a','b','c','d','e']
},
methods:{
btnClick(){
//下列方法是响应式的
//1 push方法
this.letter.push('aaa')
this.letter.push('aaa','bbb','ccc') //可以一次添加多个元素
//2 pop
this.letter.pop(); //删除数组中的最后一个元素
//3 shift
this.letter.shift();//删除数组中的第一个元素
//4 unshift
this.letter.unshift('aaa','bbb','ccc'); //往数组的最前面添加元素
/*
5 splice:删除元素/插入元素/替换元素
splice(start,)
删除元素:第二个参数传入你要删除几个元素(如果没有传第二个参数,则删除后面所有的元素)
替换元素:第二个参数表示我们要替换几个元素,后面是用于替换前面的元素
插入元素:第二个参数传0,后面跟要插入的元素
*/
this.letter.splice(1); //删除1后所有元素
this.letter.splice(1,3,'m','n','l') //替换第一个元素后的三个元素
this.letter.splice(1,0,'m','n','l') //插入元素
//6 sort
this.letter.sort(); //排序
//7 reverse
this.letter.reverse(); //反转
//注意:通过索引值修改数组中的元素(非响应式)
// this.letter[0] = "bbb" //并不是所有改变数据的方法都是响应式的
// this.letter.splice(0,1,'bbb');
//set(要修改的对象,索引值,修改后的值)
vue.set(this.letter,0,'bbbb');
}
}
})
</script>
- 作业的回顾
需求:默认第一个li是红色,点击li实现变色
<style>
.active {
color:red;
}
</style>
<body>
<div id="app">
<ul>
<li v-for="(item,index) in movices"
:class="{active:currentIndex===index}"
@click="liClick(index)">{{index}}-{{item}}</li>
</ul>
</div>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el:"#app",
data:{
movices:['海王','海贼王','加勒比','海尔兄弟'],
currentIndex:0
},
methods:{
liClick(index){
this.currentIndex = index;
}
}
})
</script>
</body>
购物车案例
- html
<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 | 过滤器}}</td> -->
<td>{{item.price | showPrice}}</td>
<td>
<button @click="decrement(index)" :disabled="item.count <= 1">-</button> <!-- 不能减到1,禁用按钮 -->
{{item.count}}
<button @click="increment(index)">+</button>
</td>
<td><button @click="removeHandler(index)">移除</button></td>
</tr>
</tbody>
</table>
<h2>总价格:{{totalPrice | showPrice}}</h2>
</div>
<h2 v-else>购物车为空</h2>
</div>
<script src="../js/vue.js"></script>
<script src="index.js"></script>
- js
const app = new Vue({
el:'#app',
data:{
books:[
{
id:1,
name:'《算法导论1》',
date:'2009-2',
price:65.40,
count:1
},
{
id:2,
name:'《算法导论2》',
date:'2009-2',
price:65.00,
count:1
},
{
id:3,
name:'《算法导论3》',
date:'2009-2',
price:65.00,
count:1
},
{
id:4,
name:'《算法导论4》',
date:'2009-2',
price:65.00,
count:1
},
]
},
methods:{
// getFinalPrice(price){
// return '¥'+ price.toFixed(2)
// },
decrement(index){
this.books[index].count --;
console.log("decrement",index);
},
increment(index){
this.books[index].count ++;
console.log("increment",index);
},
removeHandler(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;
}
*/
/*
for (let i in books){
totalPrice += this.books[i].price * this.books[i].count;
}
*/
/*
for (let book of this.books){
totalPrice += book.price * book.count;
}
return totalPrice;
*/
//高阶函数reduce
return this.books.reduce(function(prevalue,book){
return prevalue + book.price * book.count
},0)
}
},
filters:{
showPrice(price){
return '¥'+ price.toFixed(2)
}
}
})