前端MVVM实战-数据绑定(一)

数据绑定

上几节完成了对视图的初始化,但就目前来说都仅仅是静态的,在改变其data内的数据时,视图还不能实时更新,所以接下来就是比较复杂的数据绑定

数据绑定是当我们更新某一个数据时,其在视图上引用或间接引用的数据能够实时的被更新

那么如何去实现数据绑定呢?

先来看看第二章我放的图,在上面那条线中我们可以看到通过劫持监听属性的变化来通知监听者更新视图,通俗来说就是把数据的改变,在setter的时候就给截停了,然后做一些处理再通知视图做更新。当然底层不可能这么简单,在最开始时我们将data中的数据代理到了MvvmVue,数据的一切的改变都会先走MvvmVue中的setter或getter,然后在setter或getter中再去对data中的某个数据进行更新.

所以MvvmVue仅仅是数据代理,而最终做数据处理的还是data中的setter或getter

原理图

也就是说如果要实现数据绑定,需要通过数据劫持去做

Observer

已经清楚了需求,先对data中的所有数据进行数据劫持

在MvvmVue中添加observe函数调用,将data传递过去

//dataProxy.js
// 在MvvmVue函数中将数据传给observe
function MvvmVue(options) {
    this.$options = options // 得到传过来的配置
    var data = this._data = this.$options.data // 得到配置里面的data对象
    var _self = this // 保存this对象
    // 遍历属性对象JSON
    Object.keys(data).forEach(function (key) {
        // 实现属性代理
        _self._proxy(key)
    })
    // 进行所有数据监听
    observe(data)

    // 编译HTML模板
    this.$compile = new Compile(_self.$options.el || document.body, _self)
}

新建一个observer.js文件

定义一个Observer类,主要是对数据做监听

// observer.js
// 检查数据是否符合监测对象
function observe (data){
    // value必须是对象, 因为监视的是对象内部的属性
    if (!data || typeof data !== 'object') {
        return
    }
    // 使用Observer对象,处理数据
    new Observer(data)
}
// 定义Observer对象
function Observer(data) {
    this.data = data
    this.start(data) // 对数据进行监视
}
// 扩展Observer函数
Observer.prototype = {
    // 开始对数据进行监测
    start(data){
        var _self = this
        // 对该对象进行遍历
        Object.keys(data).forEach(function (key) {
            // 拿到key值和value值,进行监测
            _self.convert(key,data[key])
        })
    },
    convert(key, value){
        // 对指定属性实现响应式数据绑定
        this.defineReactive(this.data, key, value);
    },
    defineReactive(data, key,val){
        // 间接性的递归,监测更深层次的数据
        var childObj = observe(val);
        // 给data重新定义属性(添加set/get)
        Object.defineProperty(data,key,{
            enumerable: true, // 可枚举
            configurable: false, // 不能再define
            get(){
                return val
            },
            set(newVal){
                if(newVal === val){
                    return
                }
                val = newVal
                // 如果新值是一个对象的话就再进行监测
                childObj = observe(newVal)
            }
        })
    }
}

上面的代码对data中所有数据进行了getter和setter监听,在这里需要注意的一点是,为了拿到data中深层次的对象,通过类似于递归(但只是对数据进行处理并不是真正的递归)的方式去监视更深层次的数据,其他代码都比较简单就不做过多的赘述
我们能够看到在_data中也声明了有setter和getter


10.png

Dep以及watcher

9.png

如图画圈和箭头的是已经完成的,对于dep和watcher对象是什么,它是做什么的,需要深入的去解析

从图上来看,在observer监听中如果有改变就会去通知Dep数据有变化,在Dep中数据有变化就会去通知watcher数据有变,然后watcher再去进行一个视图更新

另外还有一个步骤是从Compile编译阶段到watcher,这是需要把模板上所有指令绑定的属性值在watcher中做一个存储,接着再去dep对象中添加订阅者也就是将多个watcher存储到dep中去,然后如果有更新就通过dep去发布通知多个watcher有更新

Dep是什么?

Dep作为一个发布订阅中的发布者,肩负的是当数据有更新就发布个通知,通知watcher更新视图...

从代码层面看,data数据中每一个数据对象,包括其更深层次的所有对象,每一个对象即对应一个Dep,其作用就是如果其中某一个数据对象发生了改变,那么其对应的Dep对象就应该被告知数据被改变

// 例如
data:{
x:0, // 对应Dep1对象
y:{ // 对应Dpe2对象
    z:3 // 对应Dep3对象
  }
}
watcher是什么?

如上,watcher作为一个订阅者,在收到dep发布的通知时,会立刻去更新视图

从代码层来看,watcher对象的创建时机应该是在模板编译阶段,在对指令或是双括号进行编译解析时,会得到一些数据对象,这时每一个指令或双括号都应该对应一个watcher对象,用来监听数据的更新

// 例如
{{name}} // 对应一个watcher对象
{{fruit.apple}} // 对应一个watcher对象
v-text='name' // 对应一个watcher对象
@click='change' // 对应一个watcher对象
Dep和watcher的关系

一个Dep对象可能存储多个watcher对象,这是因为一个数据可能用在多个指令或模板内,如上{{name}}和v-text='name',那么Dep就需要通知多个watcher进行更新

一个watcher对象可能存储多个dep对象,这是因为可能会出现如上面fruit.apple这样的情况,在 Dep是什么中 有写,每一个数据对象即对应一个Dep对象,这时需将fruit.apple拆成fruit和apple两个dep来看,那么就需要在fruit和apple的Dep中分别去存储这个watcher,这样不管是fruit更新,还是apple更新,都会去触发这个watcher去更新,避免了该对象的上层更新而没有通知到下一层对象的更新

目前理清楚了Dep和Watcher是什么以及其复杂的关系,那么在Dep对象中应该有通知和存储watcher功能,在Watcher对象中有存储dep和视图更新功能,接下来就可以开始写代码了

其他文章导航:

前端MVVM理论-MVC和MVP
前端MVVM理论-MVVM
前端MVVM实战-常用的几个方法和属性
前端MVVM实战-数据代理
前端MVVM实战-模板解析之双括号解析
前端MVVM实战-模板解析之事件指令和一般指令
前端MVVM实战-数据绑定(一)
前端MVVM实战-数据绑定(二)

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

推荐阅读更多精彩内容