概念
- 当数据改变后,Vue 会通知到使用该数据的代码。例如,视图渲染中使用了数据,数据改变后,视图也会自动更新。
方法:代理与监听
示意图
getter 和 setter
```javascript //需求一,得到姓名 let obj1={ 姓:”高”, 名:”圆”, 姓名(){
} console.log(“需求ー:”+obj1.姓名()) //姓名后面的活号能删掉吗?不能因为它是函数return this.姓+this.名;}
//需求二,姓名不要括号也能得出值 let obj2= { 姓:”高”, 名:”圆圆”, get 姓名(){ return this.姓+this.名 } } console.log(“需求二:” + bj2.姓名)} //使用 gettter 函数后面不需要加括号
//需求3,写入姓名
let obj3 = {
姓:”高”,
名:”圆圆”,
get 姓名(){
return this.姓+this.名 }
set 姓名(x){
this.姓 = xxx[0]
this 名 = xxx.substring(1) }
}
obj3.姓名 = ‘刘诗诗’
console.log(需求三:姓 ${obj3.姓},名 ${obj3.名}) //需求三: 姓刘,名诗诗
<a name="g6Kpv"></a>### Object.defineProperty- 可以给对象添加属性 value- 可以给对象添加 getter/settergetter/ setter 用于对属性的读写进行监控```javascriptvar _xxx = 0Object.defineProperty(obj3, xxx, {get(){return xxx}set(value){this._xxx = value}})
需求一:n 不能小于 0 (此时 n 可以被直接篡改)
let data1 = {}data1.n = 0 //n 用来的存 n 的值Object.defineproperty(data1, 'n', {get(){return this. n},set(value){if(value < 0) returnthis._n = value}})
需求二:使用代理
代理:对一个对象的读写,全权由另一对象负责
let data2 = proxy({data:{n:0}})function proxy({data}){const obj = {}Object.defineProperty(obj,'n',{get(){return data.n},set(value){if(value < 0) returndata.n = value}})return obj //obj 作为代理,此时无法直接修改数据}
当使用代理时使用了引用值
const myData = {n:0} //此时改变 myData 还是可以改变数据let data3 = proxy({data: myData})function proxy({data}){const obj = {}Object.defineProperty(obj,'n',{get(){return data.n},set(value){if(value < 0) returndata.n = value}})return obj}
需求三:当用户直接修改 myData 时,也要拦截
const myData = {n:0} //此时改变 myData 还是可以改变数据let data4 = proxy({data: myData})function proxy({data}){let value = data.nObject.defineProperty(data,'n',{ //监听get(){return value},set(newValue){if(newValue < 0) returnvalue = newValue}})const obj = {}Object.defineProperty(obj,'n',{ //代理get(){return data.n},set(value){if(value < 0) return //此时可省略data.n = value}})return obj}
data 的 bug
当 template 中使用了 n,而 data 中未定义 n
情况一:报错,vue 会检测第一层是否定义了
new Vue({el:"#app",data:{m: 0},template:`<div class="red">{{ n }}<button @click="add">添加</button></div>`,})
情况二:当第一层定义了值时,默认认为有该值。然而此时点击按钮页面无响应,因为此时没有对 obj.n 添加监听和代理。
- 原理:Object.defineProperty(obj,’n’,{}),必须有一个 ‘n’,才能进行代理和监听,无法代理和监听一开始未定义的 key。
- 解决办法:使用 Vue.set(this.obj,’n’,value) 或 this.$set(this.obj,’n’,value)。
这个 API 会新增 key,创建监听和代理,触发 UI 更新。
new Vue({el:"#app",data:{obj:{m:0}},template:`<div class="red">{{ obj.n }}<button @click="add">添加</button></div>`,methods: {add() {obj.n = 1},},})
当 data 中使用了数组时,可使用 Vue 的变异方法,Vue 对这些方法进行了包裹,实现与对象上相同的功能。
包括:shift() unshift() pop() push() splice() sort() reverse()
new Vue({el:"#app",data:{array:[1,2,3]},template:`<div class="red">{{ array }}<button @click="add">添加</button></div>`,methods: {add() {this.array.push(4) //原来的 push 方法被 Vue 篡改了},},})
模拟包裹 push
//ES6写法Class VueArray extends Array{push(...args){const oldLength = this.length //this就是当前数组super.push(...args)console.log('你 push 了')for(let i= oldLength; i < thisLength; i++){Vue.set(this, i, this[i]) //将每个新增的key都告诉Vue}}}
