vue 数据响应式

深入理解 options.data,响应式原理

const myData = {
  n:0
}
console.log(myData)
打印出{n:0}

const vm = new Vue({
  data:myData,
  template:`
  <div>{{n}}
  <button @click="add">+10</button>
  </div>
  `,
  methods:{
    add(){
      this.n+=10
    }
  }
}).$mount('#app')

//我在外面变更myData也是可以的
setTimeout(()=>{
  myData.n+=10
  console.log(myData)
  console.log(vm)
},5000)
三个console

ES6中的 getter 和 setter

let obj0 = {
  姓:"高",
  名:"圆圆",
  age:"18"
}

1、我要得到他的姓名
let obj1 = {
  姓:"高",
  名:"圆圆",
  age:"18",
  姓名(){
    return this.姓+this.名
  }
}
console.log(obj1.姓名())

2、obj1.姓名()后面这个括号我要去掉,但是还得得到姓名

姓名不需要括号也可以得出值,+个get 他就知道这是一个属性,不是函数。
这种写法叫做getter,用于获取一个值
let obj2 = {
  姓:"高",
  名:"圆圆",
  age:"18",
  get 姓名(){
    return this.姓+this.名
  }
}
console.log(obj1.姓名)

3、我要姓名可以被写 set 

let obj3 = {
  姓:"高",
  名:"圆圆",
  age:"18",
  get 姓名(){
    return this.姓+this.名
  },
  set 姓名(xxx){
    this.姓 = xxx[0]
    this.名 = xxx.substring(1)
  },
}
obj3.姓名= ’刘亦菲‘ 触发set函数 = 右边就是xxx
console.log(`姓${obj3.姓},名${obj4.名}`)
写法叫setter

通过计算属性 改变原始属性。打印出来看看是啥console.log(obj3)


D9SL4SEMW{Z5_KZVZ4LD`KP.png

我们看到这个姓名:(...)和之前的n:(...)一样,说明我们之前得到的n:(...)也是一个get set

这个姓名不是真实的属性 因为我并没一个属性叫姓名 我只有 get姓名 和set姓名。
所以浏览器在显示这个姓名的时候是 姓名:(...)
说明你确实可以对姓名进行读和写但是姓名这个属性并不存在
是通过get姓名 和set姓名完成的
推出n:(...)并不存在叫n的属性 而是有一个get n set n模拟对n的操作

但是为什么把他变为get n set n呢?

Object.defineProperty()

我们一开始定义的时候直接把get set 写在对象里面, 如果我后面想加呢?
用Object.defineProperty()
定义一个对象之后你想在他身上额外添加新的get set

var z = 0定义一个东西存放它

Object.defineProperty(obj3,'xxx',{
  get(){return z}
  set(value){z=value}
})

第一个参数写在那个对象上添加
第二个参数你要定义个什么东西 xxx
然后就写get set
get xxx(){}
我们给object3添加一个虚拟属性 有一个get 和set
你定义的这个xxx是不存在的不能使用this.xxx(死循环 get xxx 就调用xxx就继续get)

代理和监控

//修改 myData  不让他成功
//obj 中介 data 房东 禁止租客和房东联系  所以我们要监听它

let myData5 = {n:0}
let data5 = proxy2({data:myData5})

function proxy2({data}){
    let value = data.n //首先拿到n的值
    //delete data.n //删除原生的n 不写也行 声明新的虚拟对象的时候 下面会直接覆盖的
    Object.defineProperty(data,'n',{ //声明虚拟的n放啊都data上
        get(){return value},
        set(v) {
            if (v<0){
                return
            }
            value = v
        }
    })
    //上面会监听data.n(在房东手机安装监听器) 下面是代理
    const obj = {}
    Object.defineProperty(obj,'n',{
        get(){return data.n},
        set(v) {
            if (v<0){
                return
            }
            data.n = v
        }
    })
    return obj
}obj是代理data5=obj 也就是代理

console.log(`data5${data5.n}`) //0
myData5.n = -1
console.log(`更改myData5为-1失败${data5.n}`)
myData5.n = 1
console.log(`更改myData5为1成功${data5.n}`)
//以上就做到了 防止你在我不知道的情况下 修改数据

//let data5 = proxy2({data:myData5}) 眼熟吗? 跟vue的原理一模一样
// const vm = new Vue({
//     data:{n:0}
// )

//回头我们看 vue 到底对data 做了哪两件事情
  • vm = new Vue({data:myData})做了什么
    1.会让vm称为myData的代理(proxy)
    2、会对myData 的所有属性进行监控(上面只是简化了 直接用的n其实应该遍历)
    为什么要监控》?防止 myData的属性变了 vm不知道
    vm知道了又如何?知道属性变了就可以render(data)了啊
    UI = render(data) UI更新

  • 监控就是把myData所有属性 移动到value上面
    然后添加虚拟属性 读写都会被vm监听到

  • 总结
    Object.defineProperty()
    可以给对象添加属性给他一个value
    可以给对象添加getter、setter
    getter、setter用于对属性的读写进行监控

  • 代理(设计模式)
    对myData对象的属性读写 由vm对象负责
    vm就是myData的代理
    myData.n不用 就要用vm.n/this.n来操作myData.n


    示意图

数据被new Vue进行改造,加监听
n:0 变为value 添加 get n set n 读写
然后有一个代理
如果data有多个属性 进行循环即可
有对应的 get n get m get k

同理vue 对methods computed也有处理

数据响应式

什么是响应式
我打你一拳你会疼,你就是响应式的
若一个物体对外界刺激做出反应就是响应式的

vue的data是响应式的
const vm = new Vue({
data:{n:0}
})
我修改vm.n 那么UI中的n就会响应我
Vue 通过 Object.defineProperty() 做到

响应式网页 改变窗口大小内容会响应式

Vue的bug

Object.defineProperty(obj,'n',{...}) 的问题
必须要给他传一个n ,才能监听&代理obj.n
如果开发者没有给n怎么办
1.vue发出警告


shili

属性或者方法n没有定义在实例上,但是你引用了它在render的时候。
2、它只会检查第一层


N0J2`YV75$F58DX)8}A_91S.png

此时点击按钮b并没有出现在视图中
因为Vue一开始 监听obj 和 obj.a
没办法监听一开始i不存在的obj.b

如何解决
1、 直接声明好 就算写b:undefined一开始也会被监听的
2、使用Vue.set 或this.$set

setB(){
  Vue.set(this.obj,'b',1)
  this.$set(this.obj,'b',1)
}

之后就可以直接用了 不要set了
这个代码做了什么
新增属性b
自动创建代理和监听(如果没有创建过)
触发UI更新(不会立即)

data中有数组怎么办?

没有办法事先声明好,数组的长度可以一直增加 下标就是key.
难道每次修改数组都要Vue.set?

点击按钮 在数组加一个D
点击之后发现无反应。

new Vue({
  data :{
    array : ["a","b","c"]  
  }
  template:`
    <div>
    {{array}}
    <button @click = "setD">set d </button>
    </div>
`,
    methods:{
      setD(){
        this.array[3] = "d"
      }
    }
})

下面这样可以

 this.$set(array,3,'d')

难道我 数组操作都要set?
为啥不用push,push竟然可以

 this.array.push("d")

因为此时的push不是以前的push
console.log(this,array)


1

以前的数组不止着七个方法啊
为啥还有个啥mutator


2

再点开一层原型 发现才是真正的数组原型

也就是说
这个数组对象,传给vue之后。vue就会篡改数组,调用后会更新UI。中间加原型有七个方法 和以前的七个方法同名 但是代码被改了 应该就加了一个set
所以说这个push做做两个事情 1、调用以前的push 加个set

大概原理如下

class VueArray extends Array{  首先继承数组原有的属性,再声明一个push,接收一个数组
      push(...args){
        const oldLength = this.length//this就是当前数组 先看看本来长度是多少
        super.push(...args)  调用父元素上的push,你如果调我这个push方法 我就先调用我下一层的 push
        for(let i = oldLength;i<this.length;i++){
          Vue.set(this,i,this[i]) 将新增的key告诉vue
        }
      }
}
aw(~)$08{fzk@h7f}zkafq3.png

总结
对象中新增的key
Vue没有办法事先监听和代理
要使用set来新增key创建代理和监听更新UI
最好提前把属性写出来
但是数组做不到

数组新增key
也可以使用set来新增
Vue篡改了7个API来方便你对数组的操作

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,744评论 6 502
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,505评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,105评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,242评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,269评论 6 389
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,215评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,096评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,939评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,354评论 1 311
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,573评论 2 333
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,745评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,448评论 5 344
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,048评论 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,683评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,838评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,776评论 2 369
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,652评论 2 354

推荐阅读更多精彩内容