文章目录
Vue学习笔记02
vm的data数据发生变化就会重新解析模板
数据代理
什么是数据代理?
通过一个对象代理另一个对象中属性的操作(间接的操作)
//代理模式
let obj ={x:100}
let obj2 ={y:200}
Object.defineProperty(obj2,'x',{
get(){
return obj.x;
},
set(value){
obj.x = value;
}
})
在浏览器控制台查看的时候会显示…,点击只会才可以看见
Vue中的数据代理
我们发现vue的实例上,我们写在name里面的变量也是这样的
const vm=new Vue({
el:'#root',
data:{
name:'指令语法',
}
});
Vue中的数据代理
通过vm对象来代理data对象中属性的操作
data中所有的属性,最后都出现在vm身上
通过vm读name读的是data中的name,也就是修改的vm._data.name
通过vm改name改的是data中的name,也就是修改的vm._data.name
vm身上所有的属性及Vue原型上的所有属性,在Vue模板中都能使用
所以通过数据代理,更加方便地操作data中的数据,直接使用{{name}}而不用使用{{_data.name}}
基本原理
通过Object.defineProperty()把data对象中所有属性添加到vm上。
为每一个添加到vm上的属性,都指定一个getter/setter。
在getter/setter内部去操作data中对应的属性。
vm.data===date
事件处理
语法:v-on:事件=“函数名”
可以简写为@事件=“函数名”
使用@事件=“函数名(传参)"
传参时,可以使用$event传递事件对象
使用@事件=“函数名"`不传参时,默认第一个参数就是事件对象
事件的回调需要配置在methods对象中,methods里的函数最终会在vm上
<button v-on:click="showInfo1">不传参</button>
<button @click="showInfo2(这里可以传参)">传参</button>
//js
const vm=new Vue({
el:'#root',
methonds:{
showInfo(event){//this指向vm
}
}
});
事件修饰符
@事件.prevent
阻止该默认事件
@事件.stop
阻止该事件冒泡
@事件.once
事件只触发一次
@事件.capture
使用事件的捕获模式,在捕获阶段处理事件(一般是在冒泡阶段处理事件)
@事件.self
只有event,target是当前操作的元素时才触发事件
@事件.passive
事件的默认行为立即执行,无需等待事件回调结束
wheel 鼠标滚轮滚动触发 scroll 滚动条滚动触发
按键别名
键盘事件
@keydown 按下键盘触发
@keyup 按键抬起来触发(常用)
Vue常用的按键别名
回车 => enter
删除 => delete 捕获“删除”和“退格”键
退出 => esc
空格 => space
换行 => tab tab键按下之后焦点会立即边走,所以配合keydown使用
上 => up
下 => down
左 => left
右 => right
案例
@keyup.enter
回车键抬起来的时候触发
每个按键都有一个名字和编码
回车 e.key:Enter
e.keycode:13
而上面的vue别名只是方便我们写,所以说@keyup.Enter
也可以实现上述案例
注意由多个单词组成的如CapsLock在标签在中要使用@key.caps-lock
js相关用驼峰,css相关用-写法
系统修饰键:ctrl、alt、shift、meta(home)
1.配合keyup使用:按下修饰键的同时,再按下其他键,随后释放其他键,事件才被触发。
2.配合keydown使用:正常触发
.支持链式调用
比如:@click.prevent.stop
先阻止默认行为,再阻止冒泡
比如ctrl + y触发@keydown.ctrl.Y
简写整理
全程 | 简写 |
---|---|
v-model:value | 只用于表单的value属性 v-modal |
v-bind:属性名 | :属性名 |
v-on:事件 | @事件 |
计算属性与监视
data中的数据一旦发生变化,Vue模板会重新解析一遍,如果此时插值语法里面有函数一定会重新调用一遍,这样效率非常的低。
计算属性computed
对于Vue来说,data里的数据就是属性
计算属性:根据已有的属性生成新的属性
计算属性的调用时机
1.初始化时调用
2.计算所依赖的数据发生变化
说明
1.计算属性函数是通过函数将结果作为计算属性的值,把该计算属性挂在vm上,在模板中不能直接调用函数
2.初次读取计算属性和依赖的数据发生变化时计算属性会重新计算,其他时候使用缓存
new Vue({
el:'#root',
data:{
firstName:'ran',
lastName:'an'
},
computed:{//类似代理,通过firstName和lastName修改fullName
fullName:{
get(){//读取fullName时调用
return this,firstName + this.lastName
},
set(val){
this.firstName = ;
this.lastName = ;
}//fullName修改时调用
}
}
});
计算属性的简写,前提只读不改
fullName函数是通过此函数将结果作为fullName属性的值挂在vm上,所以在模板中不能直接调用该函数
new Vue({
el:'#root',
data:{
firstName:'ran',
lastName:'an'
},
computed:{
fullName(){//fullName函数是通过此函数将结果作为fullName属性的值挂在vm上,所以在模板中不能直接调用该函数
return this,firstName + this.lastName
}
}
}
});
监视属性watch
1.当监视的属性发生变化时,handler(newVal,oldVal)函数调用,初始化时不调用
2.可以监视data和computed里的属性
写法1:创建实例时已经知道了监视的属性
new Vue({
el:'#root',
data:{
firstName:'ran',
lastName:'an'
},
watch:{
isHot:{//固定配置
immediate:false; //默认false,初始化时调用handler函数
//当监视的属性发生变化时,handler调用
handler(newVal,oldVal){}
}
}
});
写法2
vm.$watch('isHot',{配置信息})
监视属性得简写,前提只有handler函数
watch:{
isHot(newVal,oldVal){}
}
vm.$watch('isHot',function(newVal,oldVal){//handler函数})
深度监视
Vue中的watch默认不监测对象内部值的改变(一层)
配置deep:true可以检测对象内部值得改变(多层)
需求:监视numbers对象里的a属性
new Vue({
el:'#root',
data:{
numbers:{
a:1,
b:1
}
},
watch:{
//numbers.a:{这样报错因为属性都是字符串形式,只是我们平时没写字符串,但是会自动转换成字符串
'numbers.a'{
handler(newVal,oldVal){}
}
}
});
需求:监视numbers对象里的a和b属性
//监控的是numbers这个对象,也就是地址的变化,a,b的变化不会触发
numbers:{
handler(newVal,oldVal){}
}
//正确写法
numbers:{
deep:true,
handler(newVal,oldVal){}
}
监视属性和计算属性的区别
computed能完成的,watch都可以完成
computed | watch |
---|---|
1.初始化时调用 2.计算所依赖的数据发生变化 | 默认是监视的属性发生变化时调用,可以通过设置immediate让初始化时调用 |
不可以进行异步操作 | 可以进行异步操作 |
class与style绑定
动态绑定class类
<!--解析之后会汇总类 class='正常的类 需要动态改变的'-->
<div class='正常的类' :class=’需要动态改变的‘>
给class绑定的变量
字符串:样式的类名不确定,需要动态指定
数组:绑定样式的个数不确定,名字也不确定
对象:个数确定名字确定,需要动态确定是否使用
data:{
classArr:['style1','style2'],
classObj:{
style1:false,//false代表不使用
style2:false
}
}
style绑定
<div :style="styleObj">
//js
data:{
styleObj:{
fontSize:'40px'
}
}
v-if和v-show
v-if的原理
根据判断条件来动态的进行增删DOM元素
v-show的原理
根据判断条件来动态的进行显示和隐藏元素
指令 | 描述 | 区别 | 适用场景 |
---|---|---|---|
v-if | 直接删除,在文档中看不见 | 为真时才生成节点渲染到页面,为假时销毁。切换成本高 | 1.适用于不频繁切换的 2.适用于多种条件场景 |
v-show | display=none,在文档中还是看得见 | 初始渲染时渲染,通过切换css实现显示和隐藏 | 初始化成本高,适用于频繁切换的 |
注意
1.v-if
,v-else-if
,v-else
三个标签需要挨着写,中间不能插入其余标签
2.template 标签可以和v-if
指令配合,不能和·v-show·配合
<template>
标签在渲染时不会被渲染
好处:使用该标签不会破环结构
列表渲染
v-for
语法:v-for="(item,index) in 数组"
根据数组的元素个数循环生成标签。item对应的是数组中的一个元素,index对应数组的下标。
语法:v-for="(val,key) in 对象"
<ul id="root">
<li v-for="(person,index) in persons" :key='index'>{{person.name}}-{{person.age}}</li>
</ul>
<script>
new Vue({
el:'#root',
data:{
persons:[
{id:'001',name:'张山',age:18},
{id:'002',name:'李山',age:19},
{id:'003',name:'刘山',age:20}
]},
});
key的作用和原理 ★
作用:减少不必要的DOM操作,提高更新效率
使用index作为key时,如果对数据进行操作破坏了顺序
1.效率低,导致已有的虚拟DOM不能复用
2.如果有输入类DOM,错误DOM更新,界面有问题
原因
vue中的key有什么作用
虚拟DOM中的key的作用
- key是虚拟DOM对象的标识,当状态中的数据发生变化时,Vue会根据[新数据]生成[新的虚拟DOM]
- 随后Vue进行[新虚拟DOM]与[旧虚拟DOM]的差异比较,比较规则
- [旧虚拟DOM]中找与[新虚拟DOM]相同的key
如果[虚拟DOM]中内容没变,直接使用之前的[真实DOM]
如果[虚拟DOM]中内容变了,则生成新的真实DOM,随后替换掉页面中之前的[真实DOM] - 如果没找到,创建新的真实DOM,随后渲染到页面
- [旧虚拟DOM]中找与[新虚拟DOM]相同的key
如何选择key
1.如果不存在对数据的逆序添加、逆序删除等破坏顺序操作,仅用于渲染列表用于展示,使用index作为key没有问题
2.最好使用唯一标识
3.如果不显示设置,默认使用index作为key
列表过滤
/*html*/
<ul id="root">
<input type="text" placeholder="请输入名字" v-model="keyWord">
<li v-for="(person,index) of persons" :key='person.id'>{{person.name}}-{{person.age}}</li>
</ul>
</body>
//js
new Vue({
el:'#root',
data:{
keyWord:'',
persons:[
{id:'001',name:'马冬梅',age:18},
{id:'002',name:'周冬雨',age:19},
{id:'003',name:'周杰伦',age:20}
]
}
思考过程
当用户输入的关键词发生变化时,就需要过滤。
怎么观察到关键词变化?watch和computed
watch实现
<li v-for="(person,index) of filPersons" :key='person.id'>{{person.name}}-{{person.age}}</li>
new Vue({
el:'#root',
data:{
keyWord:'',
persons:[
{id:'001',name:'马冬梅',age:18},
{id:'002',name:'周冬雨',age:19},
{id:'003',name:'周杰伦',age:20}
],
filPersons:[]//用于存放过滤之后的数组,不能直接修改原数组,不然数据减少了就恢复不回来了
},
watch:{
keyWord:{
immediate:true,//初始化时就调用handler,这样原始的filPersons就有值了
handler(newVal){
this.filPersons = this.persons.filter(item =>
item.name.indexOf(newVal)!== -1
)}
}
}
});
computed实现
计算属性的调用时机
1.初始化时调用
2.计算所依赖的数据发生变化
data:{
keyWord:'',
persons:[
{id:'001',name:'马冬梅',age:18},
{id:'002',name:'周冬雨',age:19},
{id:'003',name:'周杰伦',age:20}
]
},
computed:{
filPersons(){
return this.filPersons = this.persons.filter(item =>
item.name.indexOf(this.keyWord)!== -1
)
}
}
表单的注意事项
1.复选框 Vue默认读取的是checked属性,需要指定value值,且绑定的值要是数组。
如果只有一个选择框,对于我们来说只需要是否选中,所以可以不用指定value,也不用绑定数组。
2.v-model的三个修饰符
number 输入的数据是数字类型
lazy 失去焦点的瞬间收集
trim 去除开头的空格
列表排序
需求
列表的排序是针对过滤之后的元素进行排序。
<ul id="root">
<h1>人员列表</h1>
<input type="text" placeholder="请输入名字" v-model="keyWord">
<button @click="sortType=2">年龄升序</button>
<button @click="sortType=1">年龄降序</button>
<button @click="sortType=0">年龄原顺序</button>
<li v-for="(person,index) of filPersons" :key='person.id'>{{person.name}}-{{person.age}}</li>
</ul>
new Vue({
el:'#root',
data:{
sortType:0,//0代表原顺序 1 降序 2 升序
keyWord:'',
persons:[
{id:'001',name:'马冬梅',age:18},
{id:'002',name:'周冬雨',age:19},
{id:'003',name:'周杰伦',age:22},
]
},
computed:{
filPersons(){
//过滤
const arr=this.persons.filter(item => item.name.indexOf(this.keyWord)!== -1)
//判断是否需要排序
if(this.sortType){
arr.sort((a,b)=> this.sortType===1?b.age-a.age:a.age-b.age)
}
return arr;
}}
});
Vue监测数据改变的原理
Vue默认的监视是监视数据data改变,更新模板
watch配置是给程序员用的
更新时存在的问题
数据改变了,Vue也会监测到数据改变,模板会更新
数组中的元素是对象,对象里面的属性有getter和setter
//起作用了
this.persons[0].name='马老师';
this.persons[0].age= 50;
这种写法数据改变了,但是Vue没有监测到改变了,所以模板不会被更新。不能通过索引直接改变数组
this.persons[0]={id:'001',name:'马老师',age:50}
Vue监测对象改变的原理
data里面的name被修改 -> 调用vm._date里的setter->重新解析模板->生成新的虚拟DOM->新旧DOM对比->更新页面
vm.data===date
对data中的对象数据进行加工
加工的目的:响应式
//简单写法
//创建一个监视的实例对象,用于监视data中属性的变化
const obs = new Observer(data); //obs复制了data的属性,并添加了get、set方法
//准备一个vm实例对象
let vm ={};
//赋值从右往左
vm._data = data= obs;
//Observer构造函数
function Observer(obj){
//1.汇总对象中的所有属性
const.keys = Object.keys(obj);
keys.forEach((k)=>{
Object.defineProperty(this,k,{
get(){
return obj[k];
}
set(val){
//这里更新页面等操作
obj[k]=val
}
})
})
}
Vue.set()/vm.$set()
Vue.set(target,key,val)/vm.$set(target,key,val)
向响应式对象(数组)中添加一个没有的property,并确保整个新的property也是响应式(也用于setter,getter)的,且触发视图更新。
给data中的对象(数组)添加属性
局限:不能给data追加属性
target不能是vm
或者vm._data
Vue监测数组改变的原理
数组没有set与get方法,所以直接修改索引值不能被Vue监测到 --> 不能通过索引值修改数组
修改原数组的方法
push
,pop
,shift
, unshift
,splice
,sort
,reverse
使用以上7种会修改原数组的方法,Vue才承认修改了数组
这7个方法Vue进行了重写
1.调用push
2.重新解析模板。重新生成虚拟DOM ->新旧DOM对比->更新页面
总结 ★
如果监测对象中的属性修改?
通过setter实现监视,且要在new Vue时就传入要监测的数据。
1.对象中后追加的属性,Vue默认不做响应式处理,不会渲染到页面
2.使用Vue.set(target,key,val)/vm.$set(target,key,val)可以给后添加的属性做响应式
target不能是vm
或者vm._data
如何监测数组中的元素修改?
通过包裹数组更新元素的方法实现,本质是做了两件事
1.调用原生对应的方法对数组进行了修改
2.重新解析模板,进而更新界面
过滤器(Vue3.0移除)
作用:给数据进行加工
模板中使用
{{数据|过滤器名字}} //相当于把数据作为参数传给过滤器
{{数据|过滤器名字(传参)}}//这个参数作为函数的第二个参数
{{数据|过滤器名字|过滤器2}} //管道符可连续传递
//过滤器的本质就是函数
new Vue({
filters:{
timeFormater(value){
return
},
过滤器2
}
})
//全局过滤器1
Vue.filter(过滤器名,function);
//全局过滤器2
Vue.filter(过滤器名,function);