一、虚拟DOM
1、原生JS是命令式编程,当渲染在页面的数据发生一点点变化,需要整个重新渲染一编。vue.js渐进式框架有个虚拟DOM的概念,运用diff算法,比较新旧数据,相同的数据不变不重渲染,不同的部分新数据覆盖旧数据。
二、MVVM
1、MV:M是数据‘模块’,V是DOM元素‘视图’
2、VM:是指Vue对象实例。是M和V联系的桥梁
三、数据代理
1、Object.defineProperty()
let a={x:9};
let b={y:1};
Object.defineProperty(b,'x',{
get(){
return a.x ;
} ,
set(value){
a.x=value
} ,
})
2、输出vue实例对象,data下的数据存放在vm的_data对象中。而dom元素插值数据是从vm下的取的属性值。也就是说vue封装了数据代理机制(底层用了Object.defineProperty()方法)。
四、事件修饰
0、@click=handle(event)等价于@click=handle($event)
1、prevent:阻止默认行为,比如a表亲啊加链接的跳转行为会被阻止;
2、stop:阻止冒泡事件;
3、onece:事件只能执行一次;
4、capture:冒泡模式切换成捕获模式;
5、self:只有事件发生在自己身上(不是因为冒泡或者捕获触发的事件)才会触发事件;
6、passive:比如@wheel事件,只有执行完方法里的代码才会回调滚动滚动条,加了passive,会先滚动滚动条再执行方法里的行为。
7、事件修饰可以连着写,比如:@click.prevent.stop=handle()
五、键盘事件
1、event.key获取键盘按键的名称,evant.keycode获取键盘按键的代码
2、@keydown,@keyup
3、常用按键名称:enter、tab(只对@keydown有效)、eac、delete、space、top、bottom、left、right
4、特殊用法的几个按键:ctrl、alt、shift、meta
配合@keyup使用:按下按键,配合其他按键再释放其他按键,触发事件,比如ctrl+s再释放s键
配合@keydown用:正常使用
当配合@keyup使用的时候,可以指定另一个按键,如:@keyup.ctrl.k=handle(),这样就只能配合k使用了。
5、也可以配合使用按键的keycode(随时会停止维护,不推荐)
6、自定义键名:vue实例外,Vue.keycodes.自定义建名=按键编码
六、插值语法{{}}、方法methods、计算属性computed
1、当任意数据发生改变时,dom元素和插值语法中的数据或者方法(写插值语法中的防范必须带括号)会重新解析一遍
2、而计算属性只会初次加载和相关联数据发生改变的时候才会触发计算属性重新解析,因为计算属性可以缓存数据
3、计算属性中有getter方法和setter方法,当只有getter方法,没有setter方法的时候,计算属性可以简写,写在插值语法中的方法名可以不带括号
computed:{
get:function handle(){
return this.a;
},
}
简写:
computed:{
handle() {
return this.a;
},
}
七、 监视、深度监视、另一种写法、简写
1、监视:当data中的属性或者computed计算属性发生改变回调的方法。如果将immediate属性改为true,则每次进入页面的时候自动对该属性进行一次监视。
data:{
a:1,
},
watch:{
a:{
immediate:true,
handler(newValue,oldValue){
console.log("a发生改变了!")
}
}
}
2、 深度监视:当属性是嵌套的对象,监视属性中的某个属性变化,就是深度监视
如
data:{
a:{
b:2,
c:3,
}
}
//1、此时要监视a属性中的b发生变化后的回调,则加引号,读取对象a的b值
watch:{
"a.b":{
handler(newValue,oldValue){
console.log("a的b发生改变了!")
}
}
}
//2、那如果是监测a对象(a对象地址,即a={o:9})发生改变的回调呢?
watch:{
a:{
immediate:true,
handler(newValue,oldValue){
console.log("a发生改变了!")
}
}
}
//3、那如果是监测a对象中任一值发生改变的回调呢?答:将deep属性改为true值。
watch:{
a:{
deep:true,
handler(newValue,oldValue){
console.log("a的某某值发生改变了!")
}
}
}
3、深度监视:
【1】Vue中的watch默认不监测对象内部值的改变(只监测一层)
【2】加deep属性,改为true值,watch可以检测对象内部值的改变(可以检测对象多层嵌套层里面的值)
【3】但是,Vue自身是可以检测到对象内部多层数据的改变,只是Vue提供的watch属性不允许。
4、监视、深度监视,还可以这样写:
const vm=new Vue({
data:{
a:1,
}
});
vm.$watch(a,(
handle(newValue,oldValue){
console.log("a发生改变")
}
))
5、监视的简写:当只有handle回调,没有immediate、deep等其他配置项的时候,监视是可以像getter一样监视的
简写1:
watch:{
a(newValue,oldValue){
console.log("a发生改变了!")
}
}
简写2:
vm.$watch(a,function(newValue,oldValue){
console.log("a发生改变了!")
})
八、computed计算属性和watch侦听
1、computed能办到的,watch也能办到,watch能办到的computed不一定能办到,比如,watch中可以写异步函数,computed中不能写异步函数
九、什么时候用箭头函数
1、非Vue管理的函数(定时器、Promise、axios等回调函数),里面用箭头函数,这样用的this指向的是vm Vue实例或组件实例对象。
2、所有Vue管理的函数,最好写成普通函数
十、Vue侦听和watch侦听原理
1、一斑窥豹
【1】未添加setter和getter方法的对象打印出来是这样的:
【2】添加setter和getter方法的对象打印出来是这样的:
2、如果在对象本身上添加setter会造成无线递归,内存溢出,所以封装一个类似Observer的构造函数在另一人身上复刻属性并添加setter和getter方法
[异常:RangeError: Maximum call stack size exceeded at Object.get [as name]
范围错去:name属性超过Object处的最大调用堆栈大小。
3、Vue封装了一个递归查询,可以找出对象嵌套多层中的对象,并为之添加setter和getter方法,直到最后不是对象类型的数据为止,如数组、字符串、数字、Boolean、null、undefined等等。
4、 为所有哪怕深层嵌套的对象添加setter和getter之后,会将其拷贝到vm._data中,紧接着,将vm._data数据代理到vm自身上。实现Vue框架上的dom元素可实时获取vm身上的数据。如{{information.name}}。
十一、从Vue侦听原理得出,未添加setter和getter方法的非对象类属性,是不可被直接更改的
问题 一:
点击按钮,往对象a中添加一个属性b,页面不呈现b的值。是因为Vue没有侦听到b属性,b属性不具备getter和setter操作。
点击之后,数据不呈现:
2、解决办法:
【1】把a对象这个数据更新一遍,因为a身上有getter和setter:this.a={......}。
【2】用Vue自身上的set方法添加属性:Vue.set(target,key,value)。比如:Vue.set(a,'b','你很好真的很好!')。或者:this.$set(target,key,value)。效果一样。
【3】注意不能再vm自身或者根目录上,比如vm._data用set方法。
问题二:
同理,直接添加或者修改不被setter和getter的数组呢?
比如:对象里面放数组,数组里面对象,但凡对象都有setter和getter,那么中间一层的数组没有setter二号getter,那么,直接改变数组的话,页面不呈现改变后端信息!
解决办法:
【1】用this.$set(persons,0,{id:"001},name:"马老师",age:50,sex:"男")
【2】用Vue封装的操作数组:push() pop() shift() unshift() splice() sort() reserve()
<1>这些方法本质做了两件事:1、包裹Array原型链上的原生方法;2、重新解析解析模板进而更新页面。