学习资料

本文是vue2的学习笔记,包含2024学习B站黑马程序员课程,和2025年学习B站尚硅谷课程的总结和心得,难点部分有详细的理解过程和例子,适合学习和回顾知识
由于包含了两次不同来源课程的学习,知识排版略有混乱,不过无伤大雅^_^

认识Vue

什么是Vue

是一套构建用户界面的渐进式框架
Vue2官网:https://v2.cn.vuejs.org/
构建用户界面是基于数据渲染出用户可以看到的界面
渐进式就是循序渐进,不一定非得把Vue中的所有API都学完才能开发Vue,可以学一点开发一点
Vue的两种开发方式:

  1. Vue核心包开发,场景:局部模块改造
  2. Vue核心包&Vue插件&工程化,场景:整站开发

框架和库

框架就是一套完整的解决方案
库:类似工具箱,是一堆方法的集合,比如 axios、lodash、echarts等
框架:是一套完整的解决方案,实现了大部分功能,我们只需要按照一定的规则去编码即可
框架的特点:有一套必须让开发者遵守的规则或者约束
学框架就是学习的这些规则 官网

创建Vue实例(vm=vue实例对象)

核心步骤(4步):

  1. 准备容器,如
  2. 引包(官网https://v2.cn.vuejs.org/v2/guide/installation.html上找)
    — 开发版本(完整适合学习)/生产版本(压缩后的)
    1
    <script src="https://cdn.jsdelivr.net/npm/vue@2.7.16/dist/vue.js"></script>
  3. 创建Vue实例 new Vue()
  4. 指定配置项,渲染数据
    1. el:指定挂载点
    2. data提供数据
      如:
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      <div id="app">
      <!-- 这里将来会编写一些用于渲染的代码逻辑
      双大括号{{}},然后把变量名丢进去,就会把值渲染出来-->
      <h1>{{ msg }}</h1>
      <a href="#">{{ count }}</a>
      </div>
      <script src="https://cdn.jsdelivr.net/npm/vue@2.7.16/dist/vue.js"></script>

      <script>
      // 一旦引入 VueJS核心包,在全局环境,就有了 Vue 构造函数,就可以创建实例
      const app = new Vue({
      // 通过 el 配置选择器,就可以指定 Vue 管理的是哪个盒子
      el: '#app',
      //要渲染需要现有提供的数据,通过 data 提供数据
      data: {
      msg: 'Hello ',
      count: 666
      }
      })

      </script>

响应式特性

响应式就是数据变,视图对应变
如何访问 和 修改 data中的数据(响应式演示)
data中的数据, 最终会被添加到实例上
① 访问数据: “实例.属性名”
② 修改数据: “实例.属性名”= “值”

vue中的数据代理

数据代理:通过一个对象代理对另一个对象中属性的操作(读写)
vue中的数据代理

1
2
3
4
5
6
7
8
9
10
11
12
<script type="text/javascript">
let obj ={x:100}
let obj2 = {y:200}
//通过obj2调用x,获取的是obj.x的值
object.defineProperty(obj2,'x',{get(){
return obj.x
},
set(vuale){
obj.x=value
}
})
</script>

计算属性

MVVM模型

M-model 对应data数据
V-view 模板
VM- 视图模型,vue实例对象
前端主流的框架都是这个思想:把数据放在要求的位置(Model),写出模板代码(view)。里面具体怎么插入值中间的vm实例对象来操作
vue中的MVVM
插值表达式可以直接用vm上的东西和$符(vue原型)后面的原型

数据代理–js中的Object.defineProperty方法

1
2
3
4
5
6
7
8
9
10
11
12
13
let person={
name:'枫糖',
sex:'女',
}
Object.defineProperty(对象名,'属性名',{
})
Object.defineProperty(person,'home',{
value:'泽兰'
})
console.log(person)//{name:'枫糖',sex:'女',home:'泽兰'}
for (let key in person) {
console.log(key); // 只输出 'name', 'sex'
}

使用这个方法添加的属性和直接写上去的属性(name和sex)有什么区别呢?

属性默认不参与枚举

console.log(Object.keys.(person))//只有name和sex

1
2
3
4
5
6
for(let key in person){
console.log('@',person[key])
//输出的是name和sex属性的属性值,用@分隔开,还是没有home属性参与
//@ 枫糖
//@ 女
}

如果想要使用这个方法添加的属性也参与枚举,添加一行代码enumerable:true即可,控制属性是否可以枚举,默认值false

1
2
3
4
Object.defineproperty(person,'home',{
value:'泽兰'
enumerable:true
})

属性值默认不可以修改

要想修改添加代码writabe:true
控制属性是否可以被修改,默认值false

属性不可以随意删除

想要属性可以被删除添加代码configurable:true
控制属性是否可以被删除,默认值是false

get和set:让hometown和person之间联系起来

get函数,必须有返回值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
let hometown = '泽兰'
let person={
name:'枫糖',
sex:'女',
}
Object.defineProperty(person, 'home', {
//getter:当读取 person.home 时调用此函数
get: function() {
console.log('有人读取了home属性');
return _hometown; // 返回关联的内部变量值
},
//setter:当设置 person.home 时调用此函数
set: function(newValue) {
console.log('有人修改了home属性', newValue);
_hometown = newValue; // 修改关联的内部变量
},
enumerable: true, // 通常需要可枚举
configurable: true // 通常需要可配置
});

console.log(person.home); // 输出: "有人读取了home属性", 然后 "泽兰"
person.home = '星露谷'; // 输出: "有人修改了home属性 星露谷"
console.log(_hometown); // "星露谷" (内部变量被修改)
console.log(person.home); // 输出: "有人读取了home属性", 然后 "星露谷"

home 属性本身并不存储值。它的值是通过 get 函数动态返回的(这里是 _hometown 的值)。当给它赋值时,是通过 set 函数去修改关联的 _hometown 变量。

vue中的数据代理(和_data)

vm里面(data里的数据)就是用的数据代理
有人读取vm里的name,那么name属性的getter工作,获取data.name
如果有人修改vm里的name,那么name属性的setter工作,把data.name修改掉

想要获取data.name,该怎么获取?

如果直接vm.data会发现undefinded,vm.data.name更找不到
查看vm模型,在里面有_data:{}
_是一种程序员之间默认的协定,属于实例自己的私有数据
_data里面涉及到数据劫持
所以vm._data=options.data =data
所以vm._data ===data
要找data中的数据,用vm._data.name获取

总结!!!

如果能理解了就能看懂下面这段话,不理解仔细看笔记数据代理部分,或者重看B站尚硅谷vue-数据代理这部分视频
如果vue没有数据代理,那么想要获取名字,不能再{{name}},而是要{{_data.name}}
因为vm里面的是_data,开始是没有data里面的属性(name)的,而我们能够直接拿到{{name}}是因为vue通过Object,defineProperty()做了数据代理,为每一个添加到vm上的属性都指定一个getter/setter,把data里的数据放到了vm中一份,目的就是写代码更方便
vue中的数据代理

认识 简单计算属性

定义:要用的属性不存在,要通过已有属性计算得来
原理:底层借助了0bjcet.defineproperty方法提供的getter和setter
理解:比如买了三个苹果两个桃子一个西瓜,要基于每个的数量(现有的数据)计算出一共买了多少个东西(计算出的新属性)(累加函数reduce)
计算属性:基于现有的属性,计算出来的新属性。依赖的数据变化会自动重新计算

优势:与methods实现相比,内部有缓存机制(复用),效率更高,调试方便。
备注:
1.计算属性最终会出现在vm上,直接读取使用即可。
2.如果计算属性要被修改,那必须写set函数去响应修改,且set中要引起计算时依赖的数据发

语法:声明在computed配置项中(和data并列),一个计算属性对应一个对象
使用起来和普通属性一样使用
不是函数,是属性,不加括号!!!

1
2
3
4
5
6
7
8
9
computed:{
计算属性名(){
基于现有数据,编写求职逻辑
在计算属性内部,可以直接通过this访问到vm
想要用data里面的数据,用this.属性名来获取属性值
console.log(this.list)
return 结果
}
}

computed 计算属性 vs methods 方法

  1. computed 计算属性:
    作用:封装了一段对于数据的处理,求得一个结果。
    语法:

① 写在 computed 配置项中
② 作为属性,直接使用 → this.计算属性 {{ 计算属性 }}

  1. methods 方法:
    作用:给实例提供一个方法,调用以处理业务逻辑。
    语法:

① 写在 methods 配置项中
② 作为方法,需要调用 → this.方法名(){{方法名()}} @事件名=”方法名’

  1. 缓存特性(提升性能):
    计算属性会对计算出来的结果缓存,再次使用直接读取缓存依赖项变化了,会自动重新计算 →并再次缓存

完整计算属性

计算属性默认的简写,只能读取访问,不能够修改,如果要修改,需要写计算属性的完整写法
注意get方法有缓存
get在什么时候调用呢
初次读取计算属性的时候,和所依赖的数据发生变化的时候被调用

1
2
3
4
5
6
7
8
9
10
11
computed:{
计算属性名:{
get(){
一段逻辑代码(计算逻辑)
return 结果
},
set(修改的值){
一段逻辑代码(修改逻辑)
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
data:{
firstName:'枫',
lastName:'糖'
//fullName:'枫-糖'
},
computed:{
fullName:{
get(){
console.log('get被调用了')
// console.log(this)//此处的this是vm
return this.firstName + '-'+ this.lastName
}
//set什么时候调用?当fullName被修改时。
set(value){
console.log('set',value)
const arr = value.split('-')
this.firstName = arr[0]
this.lastName = arr[1]
}
}
}

计算属性简单写法

1
2
3
4
5
computed:{
fullName(){
return this.firstName+'-'+this.lastName
}
}

watch侦听器(监听器)

简单写法

场景:直接监视简单类型数据(只有一个)
作用:监视数据变化,执行一些业务逻辑或异步操作
简单写法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
data:{
data1:'西瓜'
obj:{
data2:'桃子'
}
}
watch:{
数据属性名(newValue,oldValue){

},
'对象.属性名'(newValue,oldValue){

}
}

注意:下面的数据属性名是data1,对象.属性名是’obj.data2’,watch里面监听的方法要和data里面的数据名字一致
newVlaue表示变化后的新值,oldValue表示变化之前的旧值,可以省略,用哪个写哪个

完整写法:添加额外配置项

常用在监视对象中的所有属性变化,就是有多个地方的内容需要监视和修改,不要写多个监听器,写一个里面加上deep:true即可
deep:true 对复杂类型深度监视
immmediate:true 初始化立即执行一次handler方法
上面两个看情况写在
数据属性名(){写这里}

深度监视:
(1).Vue中的watch默认不监测对象内部值的改变(一层)
(2).配置deep:true可以监测对象内部值改变(多层)。
备注:
(1).Vue自身可以监测对象内部值的改变,但Vue提供的watch默认不可以
(2).使用watch时根据数据的具体结构,决定是否采用深度监视。

完整写法和简单写法对比

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
const vm = new Vue({
el:'#root',
data:{
isHot:true,
},
watch:{
//正常写法
isHot:{
immmediate:true
deep:true
handler(newValue,oldValue){
console.lou('isHot被修改了',newValue,oldValue)
}
}
//简写
isHot(newValue,oldValue){
console.lou('isHot被修改了',newValue,oldValue)
}
}
}
})

监视多级结构中某个属性的变化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
const vm = new Vue({
el:'#root',
data:{
isHot:true,
numbers:{
a:1,
b:1
}
},
watch:{
isHot:{
'number.a':{
handler(){
console.log('a被改变了')
}
}
}
}
})

在vue外部监听

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
const vm = new Vue:({
el:'#root',
data:{
isHot:true,
numbers:{
a:1,
b:1
}
}
})
//注意,这里的isHot一定要写成'isHot'
vm.$watch:('isHot',{
//isHot被改变时,handler被调用
handler(newValue,oldValue){
console.log('isHot被改变了',newVlaue)
}
})

注意,上面的isHot一定要写成’isHot’
在js中这些要用单引号’’包裹,在vue实例中可以省略,但正常的还是要加单引号

Vue指令

认识指令

指令是 Vue 提供的带有 v- 前缀 的 特殊 标签属性,能提高程序员操作 DOM 的效率,是 vue 开发中最基础、最常用、最简单的知识点
vue会根据不同指定针对标签实现不同功能
vue 中的指令按照不同的用途可以分为如下 6 大类:

  • 内容渲染指令(v-html、v-text)
  • 条件渲染指令(v-show(控制显示与否)、v-if(控制存在与否)、v-else、v-else-if)
  • 事件绑定指令(v-on)
  • 属性绑定指令 (v-bind)
  • 双向绑定指令(v-model)
  • 列表渲染指令(v-for)

插值表达式

是一种Vue的模板语法,用来渲染出Vue提供的数据
任何可以求得结果的都叫表达式
插值表达式不能够解析标签,要解析标签用指令!!
模板里面的内容尽可能少
注意在插值语法里想要展现函数的返回值,必须要函数名()小括号()不能省略!

作用:利用表达式进行插值,渲染到页面中

表达式:是可以被求值的代码,JS引擎会讲其计算出一个结果
以下的情况都是表达式:

1
2
3
4
5
6
7
8
9
money + 100
money - 100
money * 10
money / 10
price >= 100 ? '真贵':'还行'
obj.name
arr[0]
fn()
obj.fn()

语法

插值表达式语法:

1
2
3
4
5
<h3>{{title}}<h3>
<p>{{nickName.toUpperCase()}}</p>
<p>{{age >= 18 ? '成年':'未成年'}}</p>
<p>{{obj.name}}</p>
<p>{{fn()}}</p>

错误用法

1
2
3
4
5
6
1.在插值表达式中使用的数据 必须在data中进行了提供(必须声明过)
<p>{{hobby}}</p> //如果在data中不存在hobby则会报错
2.支持的是表达式,而非语句!,比如:if for ...
<p>{{if}}</p>
3.不能在标签属性中使用 {{ }} 插值 (插值表达式只能标签中间使用)
<p title="{{username}}">我是P标签</p>

内容渲染指令v-html、v-text

v-text (类似innerText)

向其所在的标签插入文本内容,替换掉整个标签里的内容,会覆盖标签原有内容
(更多情况下还是使用插值语法,更灵活,插值语法不会替换掉本来有的其他内容)
不能够解析标签

v-html(类似 innerHTML)

向其所在的标签插入html,替换掉标签里的内容,会覆盖标签原有内容
能够识别解析html结构

v-html安全性问题

再网站上动态渲染任意HTML容易导致XSS(盗走cookie盗用你的身份)攻击
一定要在可信的内容上使用v-html
不能用在用户提交的内容上

条件渲染

v-show,v-if,v-else-if,v-else

  • v-show :调整display属性,显示与隐藏,实际上元素还在;用于切换频繁的地方
  • v-if v-else-if : 存在与否 ,用于切换频率低的地方
  • 他们是一组判断,如果前面的v-if和v-else-if 的条件一样,那么v-if判断为真就不在走v-else-if ;如果是多个v-if判断,那么他们登记一样,前面的判断为真还会走后面的v-if判断
  • v-else 后面不用写判断,写了也没用,else是最后剩下的,前面都没有那么就是它
    注意:v-if,v-else-if,v-else-if,v-else他们是紧挨在一起的,中间不允许放其他东西(比如插入一个div)打断,如果打断了,前面的奏效后面的无效了

template配合v-if使用

templat只能配合v-if不能配合v-show

1
2
3
4
<template v-if="n===1">
<h3>枫糖雾刃松瑰</h3>
<h3>虞寻歌图蓝B8017913</h3>
</template>

列表渲染 v-for 要配:key使用!

v-for使用方法

v-for="形参 in 数据池名" :key="形参.id"
v-for="(形参,index) in 数据池名" :key="index "

  • index是自动给的索引值从0开始,如果数据池里面没有id,那么就用索引值给key
  • 使用遍历生成多个同样结构的数据,必须给每个结构生成一个唯一标识
  • v-for 里面的in 可以换成of,of有迭代器的数据都能遍历(比如字符串,数组,集合,映射,nodelist ,argment

想要生成:姓名-id,的列表该怎么做

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<div id="root">
<ul>
<li v-for="p in persons" :key="p.id">
//或者这样写
//<li v-for="(p,index) in persons" :key="index">
{{p.name}}-{{p.id}}
</li>
</ul>
</div>
<script type="text/javascript">
new Vue({
el:"#root",
data:{
persons:[
{id:'001',name:'枫糖'},
{id:'002',name:'雾刃'},
{id:'003',name:'松瑰'}
]
}
})
</script>

多用于遍历数组和遍历对象,但是还有其他用法如下:

不要学的太死板,这样的遍历v-for也可以

v-for

在用v-for时 key的原理

key的作用是给节点进行标识(类似身份证号)
如果不写Key,那么vue会默认把index作为key
重点:开发中尽量使用唯一标识的值作为Key,比如id,身份证号,学号

key为index和id有什么区别

理解:key用index在对数据进行打乱顺序操作时会有问题
在数组的前面添加一个对象
v-for
v-for
添加后表面上没问题,但实际上这样效率低,同时如果用这些数据干别的事情(比如跟input框)会出现错乱
虚拟的dom上有key,但是真实的没有,因为被vue占用了

key工作原理图

index作为key工作原理图
index作为key
用id作为Key不会数据错乱:
id作为key

小结(面试题)

小结

vue中对已知列表进行过滤(模糊搜索)

比如关键字搜索筛查(模糊搜索)
获取用户输入(v-model双向绑定)->筛选数据(当用户输入的关键词发生变变化时)
思路:使用indexOf函数进行匹配查找,使用filter方法过滤,把过滤后的数据用新数组接收,把新数组作为数据池给v-for输出展示
如果用原数组,那么原来的数据会被改变,原数据不要修改

使用watch

watch
watch
但是这个样子一上来是没有数据展示的,想要开始有数据展现,巧空字符串!!
添加一行immediate:true,
先直接调用一次,调用的这一次是空字符串,全部能匹配到
巧用字符串

使用计算属性(最佳)

计算属性
里面的return 是返回给filter,外面的return是返回给数组对象

功能升级-对列表进行排序

思路:先过滤,再排序
在data里面添加sortType属性(规定升序降序原顺序分别为2,1,0)
在查找过滤后,用一个数组收集结果,对数组进行判断查看是否需要排序
使用arr.sort进行排序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
data:{
keyword:'',//搜索的关键字
sortTyper:0, //用于排序类型选择
persons:[{},{},{}]
}
computed:{
filPersons(){
//arr数组接收模糊搜索后的结果
const arr = filter((p)=>{
return p.name.indexOf(this.keyword)!==-1
})
//对arr数组进行排序判断
//如果sortType有值,进行排序
if(this.sortType){
arr.sort((p1,p2)=>{
return this.sortType===2 ? p1.age - p2.age : p2.age-p1.age
})
}
else return arr
}
}

多种排序功能

条件渲染笔记(旧)

v-show

  1. 作用: 控制元素显示与否
  2. 语法: v-show = “表达式” 表达式值为 true 显示, false 隐藏
  3. 原理: 切换 css的display:none 控制显示隐藏
  4. 场景:频繁切换显示隐藏的场景

v-if

  1. 作用: 控制元素存在与否
  2. 底层原理:根据 判断条件 控制元素的 创建 和 移除(条件渲染)
  3. 语法: v-if= “表达式” 表达式值 true显示, false 隐藏
  4. 原理: 基于条件判断,是否创建 或 移除元素节点
  5. 场景: 要么显示,要么隐藏,不频繁切换的场景
    示例代码:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    <div id="app">
    <div v-show="flag" class="box">我是v-show控制的盒子</div>
    <div v-if="flag" class="box">我是v-if控制的盒子</div>
    </div>

    <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
    <script>
    const app = new Vue({
    el: '#app',
    data: {
    flag: false
    }
    })
    </script>

v-else 和 v-else-if

  1. 作用:辅助v-if进行判断渲染,
  2. 语法:v-else v-else-if=”判断表达式”
  3. 需要紧接着v-if使用
  4. v-else 和 v-else-if二者必须同时存在,不能只存在一个
    示例代码:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22

    <div id="app">
    <p v-if="gender===1">性别:♂ 男</p>
    <p v-else>性别:♀ 女</p>
    <hr>
    <p v-if="score >=90">成绩评定A:奖励电脑一台</p>
    <p v-else-if="score >=80">成绩评定B:奖励周末郊游</p>
    <p v-else-if="score >=70">成绩评定C:奖励零食礼包</p>
    <p v-else-if="score <70">成绩评定D:惩罚一周不能玩手机</p>
    </div>

    <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
    <script>

    const app = new Vue({
    el: '#app',
    data: {
    gender: 2,
    score: 95
    }
    })
    </script>

注册事件指令 v-on(旧)

如需为DOM注册事件,及其的简单,语法如下:
作用:注册事件=提娜佳监听+提供处理逻辑

  • <button v-on:事件名="内联语句">按钮</button>
  • <button v-on:事件名="事件处理函数">按钮</button>
  • <button v-on:事件名="处理函数(实参)">按钮</button>
  • v-on: 简写为 @
    如果没有参数,默认传入一个event事件对象,event.target拿到发生事件的目标。如果有参数,后面加逗号,$evnet这样event还在,不然就找不到了
    所有被vue管理的函数都写普通函数,尽量不要写箭头函数
    普通函数看调用,箭头函数看定义
    这里如果写箭头函数,那么this指向的不是event而是windows

vue中的修饰符

事件修饰符

  1. @事件名.prevent → 阻止默认行为
    <a href="http://www.atguigu.com" @click.prevent="showInfo">点我提示信息</a>
  2. @事件名stop:阻止事件冒泡(常用)
  3. @事件名once:事件只触发一次(常用)

指令修饰符 .

通过 . 指明一些指令后缀,不同后缀封装了不同的处理操作,用于简化代码

按键修饰符:

@keydown 按下就触发,不同抬起来
@keyup 按下去松手后触发(一般用)

e.keyCode 获取按键的编码,e.key用于获取按键的名字,但是常用按键有别名,省去判断了:
.enter=回车键 (如@keyup.enter)监听键盘回车
.delete=删除键
.esc=退出键ESC
.space=空格键
.tab=换行键 (这个键要用keydown,因为这个键本身有移除焦点的功能)
.up .down .left .right 上下左右键

其他的转化为key值(按键的名字)去绑定,但注意如果这个名字是两个单词组成的,要转化为kebab-case(短横线命名)(如值为MyCat转化成@keyup.my-cat=”函数名”)

系统修饰符(特殊用法)

ctrl、alt、shift、meta
(1).配合keyup使用:按下修饰键的同时,再按下其他键,随后释放其他键,事件才被触发
(2).配合keydown使用:正常触发事件

v-model修饰符:

v-model.trim 去除首位空格
v-model.number 转数字(比如检测用户输入是不是数字,如果不是数字那么无法转数字表示用户输错了)

修饰符可以连着写

比如一边阻止默认事件,一边阻止事件冒泡
@click.prevent.stop

定制键名小技巧

Vue.config.keyCodes.自定义键名 =键码,可以去定制按键别名
@click.ctrl.y

v-on 内联语句:可执行的代码

<button @click="count--">-</button>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<div id="app">
<button @click="count--">-</button>
<span>{{ count }}</span>
<button v-on:click="count++">+</button>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
count: 100
}
})
</script>

v-on 事件处理函数

<button v-on:事件名="fn">按钮</button>
注意:

  • 事件处理函数应该写到一个跟data同级的配置项(methods)中
  • methods中的函数内部的this都指向Vue实例
  • 在methods中访问data里面的数据用this.属性名
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    <div id="app">
    <button @click="fn" >切换显示隐藏</button>
    <h1 v-show="isShow">黑马程序员</h1>
    </div>
    <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
    <script>
    const app = new Vue({
    el: '#app',
    data: {
    isShow: true
    },
    methods:{
    fn(){
    //app.isShow = !app.isShow //这样写有些麻烦,用this简单
    //在methods中访问data里面的数据用this.属性名
    this.isShow=!this.isShow
    }
    }
    })
    </script>

v-on 给事件处理函数传参

<button v-on:事件名=”fn(参数1,参数2)”>按钮

  • 如果不传递任何参数,则方法无需加小括号;methods方法中可以直接使用 e 当做事件对象
  • 如果传递了参数,则实参 $event 表示事件对象,固定用法。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    <div id="app">
    <div class="box">
    <h3>小黑自动售货机</h3>
    <button @click="buy(5)">可乐5元</button>
    <button @click="buy(10)">咖啡10元</button>
    <button @click="buy(8)">牛奶8元</button>
    </div>
    <p>银行卡余额:{{ money }}元</p>
    </div>

    <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
    <script>
    const app = new Vue({
    el: '#app',
    data: {
    money: 100
    },
    methods:{
    buy1(price){this.money-=price}
    }
    })
    </script>

属性绑定指令 v-bind

理解:比如图片需要切换,图片的url要变,用这个动态更换图片的Url
作用:动态设置html的标签属性 比如:src、url、title
语法:v-bind:属性名=”属性值(表达式)”
v-bind:可以简写成 :
比如,有一个图片,它的 src 属性值,是一个图片地址。这个地址在数据 data 中存储,则可以这样设置属性值:

  • <img v-bind:src="url" />
  • <img :src="url" /> (v-bind可以省略)
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    <div id="app">
    <img v-bind:src="imgUrl" v-bind:title="msg" alt="">
    <img :src="imgUrl" :title="msg" alt="">
    </div>
    <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
    <script>
    const app = new Vue({
    el: '#app',
    data: {
    imgUrl: './imgs/10-02.png',
    msg: 'hello 波仔'
    }
    })
    </script>

黑马小案例-波仔的学习之旅

需求:默认展示数组中的第一张图片,点击上一页下一页来回切换数组中的图片
实现思路:
1.数组存储图片路径 [‘url1’,’url2’,’url3’,…]
2.可以准备个下标index 去数组中取图片地址。
3.通过v-bind给src绑定当前的图片地址
4.点击上一页下一页只需要修改下标的值即可
5.当展示第一张的时候,上一页按钮应该隐藏。展示最后一张的时候,下一页按钮应该隐藏

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<div id="app">
<button>上一页</button>
<div>
<img src alt="">
</div>
<button>下一页</button>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
list: [
'./imgs/11-00.gif',
'./imgs/11-01.gif',
'./imgs/11-02.gif',
'./imgs/11-03.gif',
'./imgs/11-04.png',
'./imgs/11-05.png',
]
}
})
</script>

v-bind对于样式控制的增强

对于样式的切换(是否添加类)
语法
:class=”对象
适用场景:如各个标签之间的选择,只选一个,于一个类名来回切换(true,false)如果是true表示有这个对象,反之没有

:class=”数组”
适用场景:批量添加或删除类,加上之后这里面所有的类都会被添加到盒子上

这样添加一组类
- 对于样式的切换(操作style)控制单个变化 :style="样式对象" style属性名不支持带-的写法,如background-color是不对的,正确的是小驼峰写法,或者加单引号

例子:导航栏点击高亮

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<div id="app">
<ul>
<li v-for="(item, index) in list" :key="item.id" @click="activeIndex = index">
<a :class="{ active: index === activeIndex }" href="#">{{ item.name }}</a>
</li>
</ul>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
activeIndex: 2, // 记录高亮
list: [
{ id: 1, name: '京东秒杀' },
{ id: 2, name: '每日特价' },
{ id: 3, name: '品类秒杀' }
]
}
})
</script>

列表渲染指令 v-for

Vue 提供了 v-for 列表渲染指令,用来辅助开发者基于一个数组来循环渲染一个列表结构。
v-for 指令需要使用 (item, index) in arr 形式的特殊语法,其中:

  • item 是数组中的每一项
  • index 是每一项的索引,不需要可以省略
  • arr 是被遍历的数组
    此语法也可以遍历对象和数字
    1
    2
    3
    4
    5
    6
    7
    8
    9
    //遍历对象
    <div v-for="(value, key, index) in object">{{value}}</div>
    value:对象中的值
    key:对象中的键
    index:遍历索引从0开始

    //遍历数字
    <p v-for="item in 10">{{item}}</p>
    item从1 开始

小案例-小黑的书架

需求:
1.根据左侧数据渲染出右侧列表(v-for)
2.点击删除按钮时,应该把当前行从列表中删除(获取当前行的id,利用filter进行过滤)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<div id="app">
<h3>小黑的书架</h3>
<ul>
<li>
<span>《红楼梦》</span>
<span>曹雪芹</span>
<button>删除</button>
</li>
</ul>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
booksList: [
{ id: 1, name: '《红楼梦》', author: '曹雪芹' },
{ id: 2, name: '《西游记》', author: '吴承恩' },
{ id: 3, name: '《水浒传》', author: '施耐庵' },
{ id: 4, name: '《三国演义》', author: '罗贯中' }
]
}
})
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<div id="app">
<h3>小黑的书架</h3>
<ul>
<li v-for="(item, index) in booksList" :key="item.id">
<span>{{ item.name }}</span>
<span>{{ item.author }}</span>
<!-- 注册点击事件 → 通过 id 进行删除数组中的 对应项 -->
<button @click="del(item.id)">删除</button>
</li>
</ul>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
booksList: [
{ id: 1, name: '《红楼梦》', author: '曹雪芹' },
{ id: 2, name: '《西游记》', author: '吴承恩' },
{ id: 3, name: '《水浒传》', author: '施耐庵' },
{ id: 4, name: '《三国演义》', author: '罗贯中' }
]
},
methods: {
del (id) {
// console.log('删除', id)
// 通过 id 进行删除数组中的 对应项 → filter(不会改变原数组)
// filter: 根据条件,保留满足条件的对应项,得到一个新数组。
// console.log(this.booksList.filter(item => item.id !== id))
this.booksList = this.booksList.filter(item => item.id !== id)
}
}
})

v-for中的key

语法:key=”唯一值”
作用:给列表项添加的唯一标识。便于Vue进行列表项的正确排序复用
为什么加key:Vue 的默认行为会尝试原地修改元素(就地复用)
实例代码:

1
2
3
4
5
6
7
<ul>
  <li v-for="(item, index) in booksList" :key="item.id">
    <span>{{ item.name }}</span>
    <span>{{ item.author }}</span>
    <button @click="del(item.id)">删除</button>
  </li>
</ul>

注意:

  1. key 的值只能是字符串 或 数字类型
  2. key 的值必须具有唯一性
  3. 推荐使用 id 作为 key(唯一),不推荐使用 index 作为 key(会变化,不对应)

双向绑定指令 v-model

所谓双向绑定就是:

  1. 数据改变后,呈现的页面结果会更新
  2. 页面结果更新后,数据也会随之而变
    作用: 给表单元素(input、radio、select)使用,双向绑定数据,可以快速 获取设置 表单元素内容
    语法:v-model=”变量”

需求:使用双向绑定实现以下需求

  1. 点击登录按钮获取表单中的内容
  2. 点击重置按钮清空表单中的内容
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    <div id="app">
    <!--
    v-model 可以让数据和视图,形成双向数据绑定
    (1) 数据变化,视图自动更新
    (2) 视图变化,数据自动更新
    可以快速[获取]或[设置]表单元素的内容
    -->
    账户:<input type="text" v-model="username"> <br><br>
    密码:<input type="password" v-model="password"> <br><br>
    <button @click="login">登录</button>
    <button @click="reset">重置</button>
    </div>
    <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
    <script>
    const app = new Vue({
    el: '#app',
    data: {
    username: '',
    password: ''
    },
    methods: {
    login () {
    console.log(this.username, this.password)
    },
    reset () {
    this.username = ''
    this.password = ''
    }
    }
    })
    </script>

v-model作用于其他表单元素

v-model会根据空间类型自动选取正确的方式更新元素(比如单选复选文本域下拉菜单这些都会自动帮你绑定关联更新数据)
注意给到后台的都是value值,而不是展示给用户看的选择文字

收集表单数据(重点)

<input type="text"/>,v-model收集的是value值,用户输入的就是value值。
<input type="radio"/> v-model收集的是value值,且要给标签配置value值。
<input type="checkbox"/>
1.没有配置input的value属性,那么收集的就是checked(勾选 or 未勾选,是布尔值)
.配置input的value属性:
(1)v-model的初始值是非数组,那么收集的就是checked(勾选 or 未勾选,是布尔值)
(2)v-model的初始值是数组,那么收集的的就是value组成的数组

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<div id="root">
<form @submit.prevent="demo">
账号:<input type="text" v-model.trim="userInfo.account"> <br/><br/>
密码:<input type="password" v-model="userInfo.password"> <br/><br/>
年龄:<input type="number" v-model.number="userInfo.age"> <br/><br/>
性别:
<input type="radio" name="sex" v-model="userInfo.sex" value="male">
<input type="radio" name="sex" v-model="userInfo.sex" value="female"> <br/><br/>
爱好:
学习<input type="checkbox" v-model="userInfo.hobby" value="study">
打游戏<input type="checkbox" v-model="userInfo.hobby" value="game">
吃饭<input type="checkbox" v-model="userInfo.hobby" value="eat">
<br/><br/>
<select v-model="userInfo.city">
<option value="">请选择家乡</option>
<option value="beijing">北京</option>
<option value="shanghai">上海</option>
<option value="shenzhen">深圳</option>
<option value="wuhan">武汉</option>
</select>
<br/><br/>
其他信息:
<textarea v-model.lazy="userInfo.other"></textarea> <br/><br/>
<input type="checkbox" v-model="userInfo.agree">阅读并接受<a href="http://www.atguigu.com">《用户协议》</a>
<button>提交</button>
</form>
</div>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
Vue.config.productionTip = false

new Vue({
el:'#root',
data:{
userInfo:{
account:'',
password:'',
age:18,
sex:'female',
hobby:[],
city:'beijing',
other:'',
agree:''
}
},
methods: {
demo(){
console.log(JSON.stringify(this.userInfo))
}
}
})

v-model的三个修饰符

lazy:失去焦点再收集数据
number:输入字符串转为有效的数字
trim:输入首尾空格过滤

黑马综合案例-小黑记事本

指令修饰符 .
通过 . 指明一些指令后缀,不同后缀封装了不同的处理操作,用于简化代码
按键修饰符:
@keyup.enter 监听键盘回车
v-model系师傅:
v-model.trim 去除首位空格
v-model.number 转数字(比如检测用户输入是不是数字,如果不是数字那么无法转数字表示用户输错了)
事件修饰符:
@事件名.stop 阻止冒泡(比如点击子盒子不想触发父盒子)
@事件名.prevent 阻止默认行为 (比如a href一个链接,不想点击跳转
@事件名.stop.prevent —>可以连用 即阻止事件冒泡也阻止默认行为

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
  <input @keyup.enter="fn" v-model="username" type="text">
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
username: ''
},
methods: {
fn (e) {
// if (e.key === 'Enter') {
// console.log('键盘回车的时候触发', this.username)
// }

console.log('键盘回车的时候触发', this.username)
}
}
})

v-cloak指令(配合css使用)

一个特殊的属性,没有属性值,在Vue实例创建完毕并接管容器后,会删掉v-clock属性
使用css配合v-cloak来解决网速慢页面展示出{{xxx}}的问题
解决js阻塞问题
场景:比如你的vue.js因为种种原因要延迟几秒才能获取,那么此时你的页面无法渲染vue,页面可能会出现各种{{}}内容,这些不希望给用户看到

1
2
3
[v-cloak]{
display:none;
}
1
<h3 v-cloak>{{hometown}}</h3>

v-once

只读一次,v-once所在的节点再初次动态渲染之后,就视为静态资源,以后的数据改变不会引起v-once所在结构的更新,可以用于优化性能
下面例子中,不管点多少次,v-once所在标签的n都是最开始的n值,后续点按钮不会再动态渲染了

1
2
3
4
5
<div id ="root">
<h3 v-once > 初始化的数字的值是:{{n}} </h3>
<h3> 当前的数字的值是:{{n}} </h3>
<button @click="n++"> 点我数字+1 </button>
</div>

v-pre

作用:跳过其所在节点的编译过程
使用:利用它跳过没有使用指令语法,没有使用插值语法的节点,能够加快编译
v-pre

过滤器

过滤器 filter

语法

过滤器不会改变原有的数据,而是产生新的数据

  1. 注册过滤器
    全局:Vue.filter(name,callback)
    局部::new Vue({ fliter:{ } })
  2. 使用情况
    {{ xxx | 过滤器名 }}或者v-bind: 属性 ="xxx | 过滤器名"

过滤器传参

| 前面的是默认的参数(value),是一定会传递给丨后面的过滤器的,要想传递自己的参数给过滤器,在过滤器后面传递自己的格式如timeFormater('YYYY_MM_DD')
但是!此时这个timeFormater过滤器肯定需要多一个形参str收集小括号里的参数,但是这样会影响没有传参使用这个过滤器的情况
此时要给过滤器的str规定形参默认值(ES6),代表如果以后形参有传递那么用形参的格式,如果没有用默认值的形式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
div id="root">
<h2>显示格式化后的时间</h2>
<!-- 计算属性实现 -->
<h3>现在是:{{fmtTime}}</h3>
<!-- methods实现 -->
<h3>现在是:{{getFmtTime()}}</h3>
<!-- 过滤器实现 -->
<h3>现在是:{{time | timeFormater}}</h3>
<!-- 过滤器实现(传参) -->
<h3>现在是:{{time | timeFormater('YYYY_MM_DD') | mySlice}}</h3>
<h3 :x="msg | mySlice">尚硅谷</h3>
</div>

<div id="root2">
<h2>{{msg | mySlice}}</h2>
</div>
</body>

<script type="text/javascript">
Vue.config.productionTip = false
//全局过滤器
Vue.filter('mySlice',function(value){
return value.slice(0,4)
})

new Vue({
el:'#root',
data:{
time:1621561377603, //时间戳
msg:'晚上好,西西'
},
computed: {
fmtTime(){
return dayjs(this.time).format('YYYY年MM月DD日 HH:mm:ss')
}
},
methods: {
getFmtTime(){
return dayjs(this.time).format('YYYY年MM月DD日 HH:mm:ss')
}
},
//局部过滤器
filters:{
timeFormater(value,str='YYYY年MM月DD日 HH:mm:ss'){
// console.log('@',value)
return dayjs(value).format(str)
}
}
})

new Vue({
el:'#root2',
data:{
msg:'hello,atguigu!'
}
})
</script>

多个过滤器串联

上面的格式化时间过滤器继续添加要求,想要只截取前四四位年份,再添加一个过滤器进行这个事情
此时time是第一个参数传递给第一个过滤器,第一个过滤器return的返回值再传递给第二个过滤器,第二个过滤器的return的值是最后的结果
多个过滤器串联

局部过滤器和全局过滤器

局部过滤器

局部过滤器要写在实例的filters:{}里面,和data,methods,computed同级
前面展示的都是局部过滤器
局部过滤器写在vue实例里面,只有这个实例可以用
如果是局部过滤器,组件之间的过滤器不能互相使用

全局过滤器

写在vue实例上面

1
2
3
4
Vue.filter('过滤器名',function(value){
return value.slice(0,4)
})

data.now()函数返回当前时间的时间戳,但是我们想要显示格式化后的时间,这里使用一个函数
轻量级处理时间的函数day.js
BootCDM网站-day.js
显示格式化后的时间:(计算属性、methods、过滤器实现)

自定义指令

把原生dom的操作自封装(所有关于dom元素的操作都需要自己操作)
写在配置项directives:{ }里面,和data,methods,computed,filters同级

如何定义自定义指令

在元素上使用的时候要写v-自定义属性名,但是在定义的时候不加v-,直接写自定义属性名即可

自定义属性的两种写法

  1. key-value(对象写法)
    能更好地处理细节

    1
    2
    3
    4
    5
    6
    7
    8
    directives:{
    自定义属性名:{
    key1:value;
    key2:value,
    fun1(){},
    fun2(){}
    }
    }
  2. 函数写法(有些功能无法实现)
    用于需求简单的情况

1
2
3
4
5
6
7
directives:{
自定义属性名:function(){ }
}
//----或者---
directives:{
自定义属性名:(){ }
}

自定义属性函数语法

  1. 自定义属性接受两个参数
    element(自定义指令所在的元素可以简写成el)和binding(绑定对象)
    重要的是binding.value

  2. 自定义函数何时会被调用
    (1)一上来会被调用(指令与元素成功绑定时!!仅仅是在内存建立了关系,不是成功放入页面时,这里可能有坑,比如无法使用element.focus()直接实现一进入页面就获取焦点,要实现这个功能要用完整写法)
    (2)指令所在的模板(vm绑定的id=root的 div大盒子)被重新解析时

自定义指令Key-value对象写法语法

vue提供了三个固定函数可以使用
(要把函数写到自定义指令里面才会调用)
这三个函数都可以接受element和binding两个参数(前面有详细说明)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
directives:{
自定义属性名:{
key1:value;
key2:value,
//1.bind()函数,一上来调用(指令与元素成功绑定时)
bind(){
element.value = binding.value
},
//2. inserted()函数,指令所在元素被插入页面时调用
inserted(){
element.focus()
},
//3. update()函数,指令所在的模板(大div)被重新解析时
update(){
//这句话
element.value = binding.value
}
}
}

往往bind和upadta的逻辑是一样的,因此如果没有特殊要求,使用自定义属性函数写法就可以完成

自定义指令注意细节

指令名

指令定义时不加v-,但是使用时要加v-
当指令复杂有多个单词组成时,不要用小驼峰命名法
如,在元素中写<span v-big-Name="n"></span>
在调用自定义指令函数的时候还原成完整的函数写法用单引号包裹
多个单词用my-cat不要用myCat

1
2
3
4
5
6
7
directives:{
'big-number':function(element,binding){
}
//可以精简成
'big-number'(element,binding){
}
}

指令回调函数中的this

所有指令相关回调函数里的this全是window,不是vm!!

局部和全局自定义指令

前面的是局部自定义指令,只能给对应的vue实例使用,其他的vue实例不能用
想要其他vue实例都能使用自定义指令,要写成全局自定义指令(和过滤器一样的道理)
下面是全局自定义指令
Vue.directive('自定义指令名',{})
全局自定义指令
全局自定义指令

自定义属性视频小结

上面的笔记比以下详细,只多不少

需求1:定义一个v-big指令,和v-text功能类似,但会把绑定的数值放大10倍。
        需求2:定义一个v-fbind指令,和v-bind功能类似,但可以让其所绑定的input元素默认获取焦点。
        自定义指令总结:
                一、定义语法:
                            (1).局部指令:
                                        new Vue({															new Vue({
                                            directives:{指令名:配置对象}   或   		directives{指令名:回调函数}
                                        }) 																		})
                            (2).全局指令:
                                            Vue.directive(指令名,配置对象) 或   Vue.directive(指令名,回调函数)

                二、配置对象中常用的3个回调:
                            (1).bind:指令与元素成功绑定时调用。
                            (2).inserted:指令所在元素被插入页面时调用。
                            (3).update:指令所在模板结构被重新解析时调用。

                三、备注:
                            1.指令定义时不加v-,但使用时要加v-;
                            2.指令名如果是多个单词,要使用kebab-case命名方式,不要用camelCase命名。

vue监测数据改变的原理

vue如何监测对象里的数据改变的

简而言之:靠setter
这部分理解的很费解,下面是一些总结,慢慢理解
巧用字符串
vm._data是在vm对象里面创建了一个_data的属性,属性值是obs对象,同时给对象data改变地址的赋值
所以修改页面双向绑定的数据,首先经过vue对应同名属性的一层代理到_data,再经过_data的二层代理,修改到了滞于内存中的原数据data(作为数据源)
可以理解为obj间接的赋予了data中属性的get和set功能,同时_data也具备了这个功能,而vm自身中的属性因为代理了_data同样具备了这个功能,因此修改任意一个都会引起set函数进行页面渲染
就是,data从保存数据者变成了纯粹的代理,数据交给函数形参obj保管了,每次操作数据,我们找data,data就找obj
这里data和_obs里面保存的都是地址,它们指向的是同一个内存空间
下面这样是不对的,按按钮数据被修改不会被直接更新
巧用字符串

vue如何监测数组里的数据改变的

数据劫持:当数据修改了,set会拿到数据做两件事:修改数据,并重新解析模版

vue生命周期

思考理解

为什么要它?引入例子:想要一个一打开页面就让字体颜色从黑体变浅再从黑变浅的效果,那么这个渐变效果的定时器放在哪里?
我开始想的放methos但是如下!
vue中的MVVM

这个例子中,粉色框部分的函数不能够写在methods里面:如果写在里面只能有两种结果:作为回调函数使用(但是需求是一进页面字体就开始变浅再变黑再变浅循环),这里没有按钮没有点击事件之类的触发,所以不可以;
第二种通过插值表达式{{change()}}调用函数来开启,但是!!调动函数让data里的透明度数据变化会重新解析再次调用,无限循环调用change()函数形成一个指数爆炸的死循环,所以也是很不对的。

此时就需要生命周期函数mounted
mounted(){} 没有冒号!
不写在methods里面,而是和data,methods平级
调用时机:vue完成模板的解析,并把初始的(一上来第一次解析的)真实的DOM元素放入页面后(挂载完毕)调用mounted

把前面提到的定时器函数放到这里面,能够实现需求

认识声明周期

Vue生命周期:就是一个Vue实例从创建到销毁的整个过程
生命周期四个阶段:① 创建 ② 挂载 ③ 更新 ④ 销毁
1.创建阶段:创建响应式数据
2.挂载阶段:渲染模板
3.更新阶段:修改数据,更新视图
4.销毁阶段:销毁Vue实例
创建阶段和挂载阶段只会执行一次,更新阶段会执行多次

生命周期函数

本质上就是函数,但是是vue在关键时刻帮我们调用的函数
vue在帮我们调用生命周期函数的时候,this的指向是vm或组件实例对象

(生命周期又名生命周期回调函数、生命周期函数、生命周期钩子)
生命周期钩子钩子很形象了

理解:一些特定的代码要在特定的阶段之后执行,如:
发送请求:在创建阶段的最后
操作dom:在挂载阶段结束之后
写这种类型的代码就要使用声明周期钩子
Vue生命周期过程中,会自动运行一些函数,被称为【生命周期钩子】→ 让开发者可以在【特定阶段】运行自己的代码、
就是说在创建到销毁的声明周期中,开发者可以让程序在特定的阶段指定特点的函数
一共有八个特定的阶段:是上面声明周期四个阶段的开始和结束
从头到尾依次是:
beforeCreate,created,beforeMount,mounted,beforeUpdate,updated,brforeDestroy,destroyed
但是最常用的是created 和mounted
在created发送初始化渲染请求
在mounted进行dom操作
brforeDestroy释放vue以外的资源,清除定时器,延时器
语法如:
beforeCreate(){逻辑代码},created(){逻辑代码}

挂载完毕 mounted(最重要)

mounted(){} 没有冒号!
不写在methods里面,而是和data,methods平级
调用时机:vue完成模板的解析,并把初始的(一上来第一次解析的) 真实的DOM元素放入页面后(挂载完毕)调用mounted

将要销毁 beforeUpdate函数(重要)

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
	<div id="root">
<h2 :style="{opacity}">欢迎学习Vue</h2>
<button @click="opacity = 1">透明度设置为1</button>
<button @click="stop">点我停止变换</button>
</div>
</body>

<script type="text/javascript">
Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。

new Vue({
el:'#root',
data:{
opacity:1
},
methods: {
stop(){
this.$destroy()
}
},
//Vue完成模板的解析并把初始的真实DOM元素放入页面后(挂载完毕)调用mounted
mounted(){
console.log('mounted',this)
this.timer = setInterval(() => {
console.log('setInterval')
this.opacity -= 0.01
if(this.opacity <= 0) this.opacity = 1
},16)
},
beforeDestroy() {
clearInterval(this.timer)
console.log('vm即将驾鹤西游了')
},
})

</script>

小结

常用的生命周期钩子:
1.mounted: 发送ajax请求、启动定时器、绑定自定义事件、订阅消息等【初始化操作】
2.beforeDestroy: 清除定时器、解绑自定义事件、取消订阅消息等【收尾工作】
关于销毁Vue实例
1.销毁后借助Vue开发者工具看不到任何信息
2.销毁后自定义事件会失效,但原生DOM事件依然有效
3.一般不会在beforeDestroy操作数据,因为即便操作数据,也不会再触发更新流程了

注意细节

常用函数

indexOf

‘arr’.indexOf(‘A’)
如果包含,返回出现在位置的索引值,如果不包含,返回-1
只要返回值!==-1,那么就是包含
indexOf(‘’)一个空字符串是0,不是-1
indexOf

filter

这个方法不修改原来的函数,但是会返回一个新的数组

sort( )

进行排序,收到两个数据项,要升序返回a-b,要降序返回b-a

注意

插值表达式和函数

在插值语法里想要展现函数的返回值,必须要{{函数名()}}小括号()不能省略!
如果{{函数名}}这样返回的是函数代码,不是return的值

computed计算属性和watch侦听属性

computed和watch之间的区别:
1.computed能完成的功能,watch都可以完成
2.watch能完成的功能,computed不一定能完成,例如:watch可以进行异步操作
两个重要的小原则:
1.所被Vue管理的函数,最好写成普通函数,这样this的指向才是vm 或 组件实例对象。
2.所有不被Vue所管理的函数(定时器的回调函数、ajax的回调函数等),最好写成箭头函数,这样this的指向才是vm或组件实例对象。
3.计算属性不能开启异步任务去

小结:
computed计算属性和watch监听属性,同样的需求前面一般更简单,但是由于computed是根据return的返回值,异步处理只能由watch来处理(比如加监听器,监听器里面的箭头函数不归vue管理,所以这里用箭头函数没问题)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<script type="text/javascript">
Vue.config.productionTip=false //阳止 vue 在启动时生成生产提示。
const vm = new Vue({el:'#root',
data: {
firstName:'张',
lastName:'三',
fullName:'张-三'
},
watch:{
firstName(val){
setTimeout(()=>{this.fullName =val +'_'+ this.lastName
},1000);
},
TlastName(val){
this.firstName +'_'+ valthis.fullName
}
}
})
</script>

v-for key值

开发中尽量使用唯一标识的值作为Key,比如id,身份证号,学号
key用index在对数据进行打乱顺序操作时会有问题
在数组的前面添加一个对象(图片)
添加后表面上没问题,但实际上这样效率低,同时如果用这些数据干别的事情(比如跟input框)会出现错乱
虚拟的dom上有key,但是真实的没有,因为被vue占用了

v-if小组

v-if v-else-if : 存在与否 ,用于切换频率低的地方
他们是一组判断,如果前面的v-if和v-else-if 的条件一样,那么v-if判断为真就不在走v-else-if ;如果是多个v-if判断,那么他们登记一样,前面的判断为真还会走后面的v-if判断
v-else 后面不用写判断,写了也没用,else是最后剩下的,前面都没有那么就是它
注意:v-if,v-else-if,v-else-if,v-else他们是紧挨在一起的,中间不允许放其他东西(比如插入一个div)打断,如果打断了,前面的奏效后面的无效了

template配合v-if使用

templat只能配合v-if不能配合v-show

1
2
3
4
<template v-if="n===1">
<h3>枫糖雾刃松瑰</h3>
<h3>虞寻歌图蓝B8017913</h3>
</template>

其他

  1. vue中data里的数据只要发生变化,模板{{}}都要重新解析,如果里面有函数也会重新调用
  2. 注意get方法有缓存
    get在什么时候调用呢
    初次读取计算属性的时候,和所依赖的数据发生变化的时候被调用
  3. 折叠代码小技巧
    要折叠一部分代码,在这部分代码的前面和后面写
    //#region
    //#endregion
  4. 指令是不能脱离元素存在的
  5. 回调函数:我们定义的我们没执行,但是最终执行力