Vue--从vue2入门到了解
学习资料
本文是vue2的学习笔记,包含2024学习B站黑马程序员课程,和2025年学习B站尚硅谷课程的总结和心得,难点部分有详细的理解过程和例子,适合学习和回顾知识
由于包含了两次不同来源课程的学习,知识排版略有混乱,不过无伤大雅^_^
认识Vue
什么是Vue
是一套构建用户界面的渐进式框架
Vue2官网:https://v2.cn.vuejs.org/
构建用户界面是基于数据渲染出用户可以看到的界面
渐进式就是循序渐进,不一定非得把Vue中的所有API都学完才能开发Vue,可以学一点开发一点
Vue的两种开发方式:
- Vue核心包开发,场景:局部模块改造
- Vue核心包&Vue插件&工程化,场景:整站开发
框架和库
框架就是一套完整的解决方案
库:类似工具箱,是一堆方法的集合,比如 axios、lodash、echarts等
框架:是一套完整的解决方案,实现了大部分功能,我们只需要按照一定的规则去编码即可
框架的特点:有一套必须让开发者遵守的规则或者约束
学框架就是学习的这些规则 官网
创建Vue实例(vm=vue实例对象)
核心步骤(4步):
- 准备容器,如
- 引包(官网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>
- 创建Vue实例 new Vue()
- 指定配置项,渲染数据
- el:指定挂载点
- 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中的数据代理
数据代理:通过一个对象代理对另一个对象中属性的操作(读写)
1 | <script type="text/javascript"> |
计算属性
MVVM模型
M-model 对应data数据
V-view 模板
VM- 视图模型,vue实例对象
前端主流的框架都是这个思想:把数据放在要求的位置(Model),写出模板代码(view)。里面具体怎么插入值中间的vm实例对象来操作
插值表达式可以直接用vm上的东西和$符(vue原型)后面的原型
数据代理–js中的Object.defineProperty方法
1 | let person={ |
使用这个方法添加的属性和直接写上去的属性(name和sex)有什么区别呢?
属性默认不参与枚举
console.log(Object.keys.(person))
//只有name和sex
1 | for(let key in person){ |
如果想要使用这个方法添加的属性也参与枚举,添加一行代码enumerable:true
即可,控制属性是否可以枚举,默认值false
1 | Object.defineproperty(person,'home',{ |
属性值默认不可以修改
要想修改添加代码writabe:true
控制属性是否可以被修改,默认值false
属性不可以随意删除
想要属性可以被删除添加代码configurable:true
控制属性是否可以被删除,默认值是false
get和set:让hometown和person之间联系起来
get函数,必须有返回值
1 | let hometown = '泽兰' |
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中一份,目的就是写代码更方便
认识 简单计算属性
定义:要用的属性不存在,要通过已有属性计算得来
原理:底层借助了0bjcet.defineproperty方法提供的getter和setter
理解:比如买了三个苹果两个桃子一个西瓜,要基于每个的数量(现有的数据)计算出一共买了多少个东西(计算出的新属性)(累加函数reduce)
计算属性:基于现有的属性,计算出来的新属性。依赖的数据变化会自动重新计算
优势:与methods实现相比,内部有缓存机制(复用),效率更高,调试方便。
备注:
1.计算属性最终会出现在vm上,直接读取使用即可。
2.如果计算属性要被修改,那必须写set函数去响应修改,且set中要引起计算时依赖的数据发
语法:声明在computed配置项中(和data并列),一个计算属性对应一个对象
使用起来和普通属性一样使用
不是函数,是属性,不加括号!!!
1 | computed:{ |
computed 计算属性 vs methods 方法
- computed 计算属性:
作用:封装了一段对于数据的处理,求得一个结果。
语法:
① 写在 computed 配置项中
② 作为属性,直接使用 → this.计算属性 {{ 计算属性 }}
- methods 方法:
作用:给实例提供一个方法,调用以处理业务逻辑。
语法:
① 写在 methods 配置项中
② 作为方法,需要调用 → this.方法名(){{方法名()}}
@事件名=”方法名’
- 缓存特性(提升性能):
计算属性会对计算出来的结果缓存,再次使用直接读取缓存依赖项变化了,会自动重新计算 →并再次缓存
完整计算属性
计算属性默认的简写,只能读取访问,不能够修改,如果要修改,需要写计算属性的完整写法
注意get方法有缓存
get在什么时候调用呢
初次读取计算属性的时候,和所依赖的数据发生变化的时候被调用
1 | computed:{ |
1 | data:{ |
计算属性简单写法
1 | computed:{ |
watch侦听器(监听器)
简单写法
场景:直接监视简单类型数据(只有一个)
作用:监视数据变化,执行一些业务逻辑或异步操作
简单写法
1 | data:{ |
注意:下面的数据属性名是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 | const vm = new Vue({ |
监视多级结构中某个属性的变化
1 | const vm = new Vue({ |
在vue外部监听
1 | const vm = new Vue:({ |
注意,上面的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 | money + 100 |
语法
插值表达式语法:
1 | <h3>{{title}}<h3> |
错误用法
1 | 1.在插值表达式中使用的数据 必须在data中进行了提供(必须声明过) |
内容渲染指令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 | <template v-if="n===1"> |
列表渲染 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 | <div id="root"> |
多用于遍历数组和遍历对象,但是还有其他用法如下:
不要学的太死板,这样的遍历v-for也可以
在用v-for时 key的原理
key的作用是给节点进行标识(类似身份证号)
如果不写Key,那么vue会默认把index作为key
重点:开发中尽量使用唯一标识的值作为Key,比如id,身份证号,学号
key为index和id有什么区别
理解:key用index在对数据进行打乱顺序操作时会有问题:
在数组的前面添加一个对象
添加后表面上没问题,但实际上这样效率低,同时如果用这些数据干别的事情(比如跟input框)会出现错乱
虚拟的dom上有key,但是真实的没有,因为被vue占用了
key工作原理图
index作为key工作原理图
用id作为Key不会数据错乱:
小结(面试题)
)
vue中对已知列表进行过滤(模糊搜索)
比如关键字搜索筛查(模糊搜索)
获取用户输入(v-model双向绑定)->筛选数据(当用户输入的关键词发生变变化时)
思路:使用indexOf函数进行匹配查找,使用filter方法过滤,把过滤后的数据用新数组接收,把新数组作为数据池给v-for输出展示
如果用原数组,那么原来的数据会被改变,原数据不要修改
使用watch
但是这个样子一上来是没有数据展示的,想要开始有数据展现,巧空字符串!!
添加一行immediate:true,
先直接调用一次,调用的这一次是空字符串,全部能匹配到
使用计算属性(最佳)
里面的return 是返回给filter,外面的return是返回给数组对象
功能升级-对列表进行排序
思路:先过滤,再排序
在data里面添加sortType属性(规定升序降序原顺序分别为2,1,0)
在查找过滤后,用一个数组收集结果,对数组进行判断查看是否需要排序
使用arr.sort进行排序
1 | data:{ |
条件渲染笔记(旧)
v-show
- 作用: 控制元素显示与否
- 语法: v-show = “表达式” 表达式值为 true 显示, false 隐藏
- 原理: 切换 css的display:none 控制显示隐藏
- 场景:频繁切换显示隐藏的场景
v-if
- 作用: 控制元素存在与否
- 底层原理:根据 判断条件 控制元素的 创建 和 移除(条件渲染)
- 语法: v-if= “表达式” 表达式值 true显示, false 隐藏
- 原理: 基于条件判断,是否创建 或 移除元素节点
- 场景: 要么显示,要么隐藏,不频繁切换的场景
示例代码: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
- 作用:辅助v-if进行判断渲染,
- 语法:v-else v-else-if=”判断表达式”
- 需要紧接着v-if使用
- 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中的修饰符
事件修饰符
- @事件名.prevent → 阻止默认行为
如<a href="http://www.atguigu.com" @click.prevent="showInfo">点我提示信息</a>
- @事件名stop:阻止事件冒泡(常用)
- @事件名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 | <div id="app"> |
v-bind对于样式控制的增强
对于样式的切换(是否添加类)
语法
:class=”对象
适用场景:如各个标签之间的选择,只选一个,于一个类名来回切换(true,false)如果是true表示有这个对象,反之没有
:class=”数组”
适用场景:批量添加或删除类,加上之后这里面所有的类都会被添加到盒子上
例子:导航栏点击高亮
1 | <div id="app"> |
列表渲染指令 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 | <div id="app"> |
1 | <div id="app"> |
v-for中的key
语法:key=”唯一值”
作用:给列表项添加的唯一标识。便于Vue进行列表项的正确排序复用
为什么加key:Vue 的默认行为会尝试原地修改元素(就地复用)
实例代码:
1 | <ul> |
注意:
- key 的值只能是字符串 或 数字类型
- key 的值必须具有唯一性
- 推荐使用 id 作为 key(唯一),不推荐使用 index 作为 key(会变化,不对应)
双向绑定指令 v-model
所谓双向绑定就是:
- 数据改变后,呈现的页面结果会更新
- 页面结果更新后,数据也会随之而变
作用: 给表单元素(input、radio、select)使用,双向绑定数据,可以快速 获取 或 设置 表单元素内容
语法:v-model=”变量”
需求:使用双向绑定实现以下需求
- 点击登录按钮获取表单中的内容
- 点击重置按钮清空表单中的内容
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 | <div id="root"> |
1 | Vue.config.productionTip = false |
v-model的三个修饰符
lazy:失去焦点再收集数据
number:输入字符串转为有效的数字
trim:输入首尾空格过滤
黑马综合案例-小黑记事本
指令修饰符 .
通过 . 指明一些指令后缀,不同后缀封装了不同的处理操作,用于简化代码
按键修饰符:
@keyup.enter 监听键盘回车
v-model系师傅:
v-model.trim 去除首位空格
v-model.number 转数字(比如检测用户输入是不是数字,如果不是数字那么无法转数字表示用户输错了)
事件修饰符:
@事件名.stop 阻止冒泡(比如点击子盒子不想触发父盒子)
@事件名.prevent 阻止默认行为 (比如a href一个链接,不想点击跳转
@事件名.stop.prevent —>可以连用 即阻止事件冒泡也阻止默认行为
1 | <input @keyup.enter="fn" v-model="username" type="text"> |
v-cloak指令(配合css使用)
一个特殊的属性,没有属性值,在Vue实例创建完毕并接管容器后,会删掉v-clock属性
使用css配合v-cloak来解决网速慢页面展示出{{xxx}}
的问题
解决js阻塞问题
场景:比如你的vue.js因为种种原因要延迟几秒才能获取,那么此时你的页面无法渲染vue,页面可能会出现各种{{}}
内容,这些不希望给用户看到
1 | [v-cloak]{ |
1 | <h3 v-cloak>{{hometown}}</h3> |
v-once
只读一次,v-once所在的节点再初次动态渲染之后,就视为静态资源,以后的数据改变不会引起v-once所在结构的更新,可以用于优化性能
下面例子中,不管点多少次,v-once所在标签的n都是最开始的n值,后续点按钮不会再动态渲染了
1 | <div id ="root"> |
v-pre
作用:跳过其所在节点的编译过程
使用:利用它跳过没有使用指令语法,没有使用插值语法的节点,能够加快编译
过滤器
过滤器 filter
语法
过滤器不会改变原有的数据,而是产生新的数据
- 注册过滤器
全局:Vue.filter(name,callback)
局部::new Vue({ fliter:{ } }) - 使用情况
{{ xxx | 过滤器名 }}
或者v-bind: 属性 ="xxx | 过滤器名"
过滤器传参
| 前面的是默认的参数(value),是一定会传递给丨后面的过滤器的,要想传递自己的参数给过滤器,在过滤器后面传递自己的格式如timeFormater('YYYY_MM_DD')
但是!此时这个timeFormater过滤器肯定需要多一个形参str收集小括号里的参数,但是这样会影响没有传参使用这个过滤器的情况
此时要给过滤器的str规定形参默认值(ES6),代表如果以后形参有传递那么用形参的格式,如果没有用默认值的形式
1 | div id="root"> |
多个过滤器串联
上面的格式化时间过滤器继续添加要求,想要只截取前四四位年份,再添加一个过滤器进行这个事情
此时time是第一个参数传递给第一个过滤器,第一个过滤器return的返回值再传递给第二个过滤器,第二个过滤器的return的值是最后的结果
局部过滤器和全局过滤器
局部过滤器
局部过滤器要写在实例的filters:{}里面,和data,methods,computed同级
前面展示的都是局部过滤器
局部过滤器写在vue实例里面,只有这个实例可以用
如果是局部过滤器,组件之间的过滤器不能互相使用
全局过滤器
写在vue实例上面
1 | Vue.filter('过滤器名',function(value){ |
data.now()函数返回当前时间的时间戳,但是我们想要显示格式化后的时间,这里使用一个函数
轻量级处理时间的函数day.js
BootCDM网站-day.js
显示格式化后的时间:(计算属性、methods、过滤器实现)
自定义指令
把原生dom的操作自封装(所有关于dom元素的操作都需要自己操作)
写在配置项directives:{ }
里面,和data,methods,computed,filters同级
如何定义自定义指令
在元素上使用的时候要写v-自定义属性名
,但是在定义的时候不加v-,直接写自定义属性名即可
自定义属性的两种写法
key-value(对象写法)
能更好地处理细节1
2
3
4
5
6
7
8directives:{
自定义属性名:{
key1:value;
key2:value,
fun1(){},
fun2(){}
}
}函数写法(有些功能无法实现)
用于需求简单的情况
1 | directives:{ |
自定义属性函数语法
自定义属性接受两个参数
element(自定义指令所在的元素可以简写成el)和binding(绑定对象)
重要的是binding.value自定义函数何时会被调用
(1)一上来会被调用(指令与元素成功绑定时!!仅仅是在内存建立了关系,不是成功放入页面时,这里可能有坑,比如无法使用element.focus()直接实现一进入页面就获取焦点,要实现这个功能要用完整写法)
(2)指令所在的模板(vm绑定的id=root的 div大盒子)被重新解析时
自定义指令Key-value对象写法语法
vue提供了三个固定函数可以使用
(要把函数写到自定义指令里面才会调用)
这三个函数都可以接受element和binding两个参数(前面有详细说明)
1 | directives:{ |
往往bind和upadta的逻辑是一样的,因此如果没有特殊要求,使用自定义属性函数写法就可以完成
自定义指令注意细节
指令名
指令定义时不加v-,但是使用时要加v-
当指令复杂有多个单词组成时,不要用小驼峰命名法
如,在元素中写<span v-big-Name="n"></span>
在调用自定义指令函数的时候还原成完整的函数写法用单引号包裹
多个单词用my-cat不要用myCat
1 | directives:{ |
指令回调函数中的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但是如下!
这个例子中,粉色框部分的函数不能够写在methods里面:如果写在里面只能有两种结果:作为回调函数使用(但是需求是一进页面字体就开始变浅再变黑再变浅循环),这里没有按钮没有点击事件之类的触发,所以不可以;
第二种通过插值表达式{{change()}}
调用函数来开启,但是!!调动函数让data里的透明度数据变化会重新解析再次调用,无限循环调用change()函数形成一个指数爆炸的死循环,所以也是很不对的。
此时就需要生命周期函数mountedmounted(){}
没有冒号!
不写在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 | <div id="root"> |
小结
常用的生命周期钩子:
1.mounted: 发送ajax请求、启动定时器、绑定自定义事件、订阅消息等【初始化操作】
2.beforeDestroy: 清除定时器、解绑自定义事件、取消订阅消息等【收尾工作】
关于销毁Vue实例
1.销毁后借助Vue开发者工具看不到任何信息
2.销毁后自定义事件会失效,但原生DOM事件依然有效
3.一般不会在beforeDestroy操作数据,因为即便操作数据,也不会再触发更新流程了
注意细节
常用函数
indexOf
‘arr’.indexOf(‘A’)
如果包含,返回出现在位置的索引值,如果不包含,返回-1
只要返回值!==-1,那么就是包含
indexOf(‘’)一个空字符串是0,不是-1
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 | <script type="text/javascript"> |
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 | <template v-if="n===1"> |
其他
- vue中data里的数据只要发生变化,模板
{{}}
都要重新解析,如果里面有函数也会重新调用 - 注意get方法有缓存
get在什么时候调用呢
初次读取计算属性的时候,和所依赖的数据发生变化的时候被调用 - 折叠代码小技巧
要折叠一部分代码,在这部分代码的前面和后面写
//#region
//#endregion - 指令是不能脱离元素存在的
- 回调函数:我们定义的我们没执行,但是最终执行力