前端,VUE学习记录(2)
本文接着第一章的内容继续叙述我的Vue学习过程,随着对Vue的学习越来越深入,我们会发现很多知识逐渐变得越来越抽象,接下来我会用很多我写的代码图来展示我学习的过程,并解释一些概念性的东西例如什么是Vue响应式等。注:本人水平有限,由于文章是我本人通过学习理解后总结出的,如有写的不好或者写错的地方欢迎私信我,并温柔的指出。谢谢阅览。
目录:
(1)getter 和 setter
(2)代理和监听
(3)什么是数据响应式
(4)数组的变异方法
(5)computed属性
(6)watch属性
(7)watch的deep选项
(8)computed v.s watch
(1)getter 和 setter
getter:
如图所示,get的用法就是让函数执行
那么有get 就有会有set,set用来改写函数里面的值,如何使用set呢?

set 姓名(xxx)xxx是一个新的值,set必须接受一个新的值
那么当你创建完一个对象后,你还想给他添加get和setter就可以使用Object.defineProperty
那么这玩意有啥用?
答:可以给对象添加属性value
可以给对象添加getter/ setter
getter/ setter 用于对属性的读写进行监控
例:
(2)代理和监听
监听:
代理:

小结:
写了这么多,那么什么是代理呢?看起来非常的抽象也不好理解,其实代理就是一种设计模式
对myData对象的属性读写,全权由另一个对象vm负责
那么vm就是myData的代理(类似于房东租房,找中介代理)
比如myData.n不用,偏要用vm.n来操作myData.n
如果用图来表示就是以下:
代理和监听其实就有点类似于租房中的中介,代理呢就是一个中介,你说你要1000块去租他的房子,然后中介把你的话原封不动传递给房东,监听呢就是为了防止你绕过中介直接去和房东谈,在房东手机里放个监听,你跟他谈中介就会知道。
vm=new Vue({data:myData})
一、会让vm成为myData的代理(proxy)
二、会对myData的所有属性进行监控
为什么要监控,为了防止myData的属性变了,vm不知道
vm知道了又如何?知道属性变了就可以调用render(data)
UI=render(data)
(3)什么是数据响应式
学到这其实我们也大概能理解什么是Vue的响应式了形象生动的描述就是:
答:我打一拳,你会喊疼,那你就是响应式的
若一个物体能对外界的刺激做出反应,它就是响应式的
Vue的data就是响应式的:
const vm= new Vue({data:{n:0}})
我如果修改vm.n,那么UI中的n就会响应我
响应式网页是啥?
答:如果我改变窗口大小,网页内容会做出响应,那就是响应式网页
简单说就是用户更改数据(Data)时,视图可以自动刷新,页面UI能够响应数据变化。 Vue就是通过getter 和setter来对数据进行操作,通过get()和set()函数可以生成一个虚拟属性,来直接调用函数操作数据。 此外,还需要一个重要的API,那就是Object.defineProperty,因为对象被定义完成后,想要更改或添加属性(像是get和set这样的属性),只能通过这个Object.defineProperty来添加。接着需要实现对数据属性的读写进行监控。能够监控就意味着能让vm(一般生成的实例)能够知道数据有变化,从而触发render(data)函数,页面UI就会做出响应。
补充小知识:data是有BUG的!
Object.defineProperty的问题:
Object.defineProperty(obj,'n',{...})
必须要有一个'n',才能监听&代理obj,n是吧
如果一个前端,没有给n怎么办?
这样子Vue会报错,你没有办法在n没有被定义的情况下使用n
解决办法:vue只监听第一层
但是这样的话点击这个按钮并不会有反应,因为vue一直在监听a
有遇到问题了!好烦,怎么解决,往下学习
1.那我不给b值,我给他一个undefined,告诉vue我虽然没值,但是我是有一个b的key
但是工作中你不可能要求别人去写这个b
所以vue提供了一个新的api
新的API
给b一个新的值,这样点击button后数值就会变
Vue.set 和 vm.$set ,这就是vue提供的两个新的api
作用:
新增key
自动创建代理和监听(如果没有创建过)
触发UI更新(但并不会立刻更新)
举例:
this.$set(this.object,'m',100)
(4)数组的变异方法
紧接上文,那么如果data中有数组怎么办?
你没法提前声明所有key
那么我们用set可不可以?
当然可以,但是这样我继续往下加呢?我不能每往后加就写一个set吧
我们可以改用push,但是要注意这个push不是以前js中数组的push了
成功了!
为什么呢?原因就在于vue在获取到数组后,对这个数组进行了改造,他会在中间加一层原型为:
pop,push,reverse,shift,sort,splice,unshift
如果你分析了源码,其实变异方法就是使用了继承,通过继承JS的push后再添加新的功能。
最终总结:
对象中新增的key
Vue没有办法事先监听和代理
要使用set来新增key,创建监听和代理,更新UI
最好提前把属性都写出来,不要新增key
但数组做不到【不新增ky】
数组中新增的key
也可用set来新增key,且创建监听和代理,更新UI
不过Vue作者篡改了7个API方便你对数组进行增删
这7个API会自动处理监听和代理,并更新UI
(5)computed属性
用途:
被计算出来的属性就是计算属性
用代码来演示其使用:
比如说我们现在有一个表,是由姓名,性别组成,那么我们要实现筛选男的和女的,在不使用computed的时候,我们的代码是这样的:
(注意下面的代码并非完全。只是为了演示构造选项的用法)
Vue.config.productionTip = false; let id = 0; const createUser = (name, gender) => { id += 1; return { id: id, name: name, gender: gender }; }; new Vue({ data() { return { users: [ createUser("方方", "男"), createUser("圆圆", "女"), createUser("小新", "男"), createUser("小葵", "女") ], gender: "" }; }, computed: { displayUsers() { const hash = { male: "男", female: "女" }; const { users, gender } = this; if (gender === "") { return users; } else if (typeof gender === "string") { return users.filter(u => u.gender === hash[gender]); } else { throw new Error("gender 的值是意外的值"); } } }, methods: { setGender(string) { this.gender = string; } }, template: ` <div> <div> <button @click="setGender('') ">全部</button> <button @click="setGender('male')">男</button> <button @click="setGender('female')">女</button></div> <ul> <li v-for="(u,index) in displayUsers" :key="index">{{u.name}} - {{u.gender}}</li> </ul> </div> ` }).$mount("#app");
你可以看到我们的methods中有很多重复的东西,并且代码可读性不高
那我们使用computed后:
Vue.config.productionTip = false; let id = 0; const createUser = (name, gender) => { id += 1; return { id: id, name: name, gender: gender }; }; new Vue({ data() { return { users: [ createUser("方方", "男"), createUser("圆圆", "女"), createUser("小新", "男"), createUser("小葵", "女") ], gender: "" }; }, computed: { displayUsers() { const hash = { male: "男", female: "女" }; const { users, gender } = this; if (gender === "") { return users; } else if (typeof gender === "string") { return users.filter(u => u.gender === hash[gender]); } else { throw new Error("gender 的值是意外的值"); } } }, methods: { setGender(string) { this.gender = string; } }, template: ` <div> <div> <button @click="setGender('') ">全部</button> <button @click="setGender('male')">男</button> <button @click="setGender('female')">女</button></div> <ul> <li v-for="(u,index) in displayUsers" :key="index">{{u.name}} - {{u.gender}}</li> </ul> </div> ` }).$mount("#app");
最终就能简化成上面这个样子。
computed和watched最大的区别就是computed有缓存,当你点了按钮一次后,再次点击他他就不会再运算了。computed是计算属性,而watch可能做别的事情(如上报数据)
(6)watch属性
whatch-侦听
一旦data变化,就执行的函数
options.watch的用法
this.$watch用法
deep,immediate含义
watch在做撤销功能时有得天独厚的优势
代码演示:
Vue.config.productionTip = false; new Vue({ data: { n: 0, history: [], inUndoMode: false }, watch: { n: function(newValue, oldValue) { console.log(this.inUndoMode); if (!this.inUndoMode) { this.history.push({ from: oldValue, to: newValue }); } } }, // 不如用 computed 来计算 displayName template: ` <div> {{n}} <hr /> <button @click="add1">+1</button> <button @click="add2">+2</button> <button @click="minus1">-1</button> <button @click="minus2">-2</button> <hr/> <button @click="undo">撤销</button> <hr/> {{history}} </div> `, methods: { add1() { this.n += 1; }, add2() { this.n += 2; }, minus1() { this.n -= 1; }, minus2() { this.n -= 2; }, undo() { const last = this.history.pop(); this.inUndoMode = true; console.log("ha" + this.inUndoMode); const old = last.from; this.n = old; // watch n 的函数会异步调用 this.$nextTick(() => { this.inUndoMode = false; }); } } }).$mount("#app");
添加后
撤销后
watch也可以实现computed的计算但是不是很推荐。因为写出来的代码看起来很蠢
(7)watch的deep选项
deep选项是干啥的,deep选项的语法为deep:true,如果想要解释它的意思首先我们需要看一段代码:

此时有三个按钮
第一个改变n的值,第二个改变obj中a的值,第三个改变obj本身的地址
那么一般情况下第二个如果你去watch监听他,他是不会打印变了的,那么如果你觉得他是变了的,你可以用deep:true,让他监听到,就是往不往里面深入的看
总结就是:如果object.a变了,请问object算不算也变了
如果你需要答案是【也变了】,那么就用deep:true;
如果你需要答案是【没有变】,那么就用deep:false;
deep的意思是,监听object的时候是否往深了看。
(8)computed v.s watch
computed计算属性,watch监听
watch 和 computed 相比,computed 是计算出一个属性,computed有缓存:如果computed属性依赖的属性没有变化,那么computed实行就不会重新计算,而watch可能是用来做别的事情(如上报数据)

浙公网安备 33010602011771号