Vue MVVM理解及实现

MVVM

简单地说就是数据驱动视图,视图改变(事件)也可以改变数据,就是双向绑定的概念。

实现

为了监听数据的改变,从而响应到视图上,用的是Vue双向绑定的核心Object.definePrototype(obj,key,{...}),编写Observer.js来实现。若set被触发,通知所有的订阅者(dep中存储的是所有订阅者实例对象),且在get中引入Dep.target,仅在添加watcher时主动赋值,防止之后多次添加watcher,并且get返回当前的val值。
Object.defineProperty(data,key,{
        enumerable: true, // 可枚举,可被Object.value()等遍历方法所遍历
        configurable: true, // 可再重新定义,即可被修改,可被删除, 默认为false
        get: function(){
            // console.log(Dep.target)
            // Dep.target现在其实为null,但是在watcher.js中每次get都将watch自身添加到全局的Dep.target中
            // 等到value获取完毕,再将Dep.target清空
            // Dep.target作为闭包,在函数中保持了dep的存在
            // 如果没有Dep.target,dep会被清除,在set中就无法通过dep.nptify()来出发watcher了
            // Dep.target && dep.addSub(Dep.target)
            if(Dep.target){
                dep.addSub(Dep.target) // 添加一个订阅者
            }
            return val
        },
        set: function(newVal){
            console.log('值变化')
            if(newVal === val) return
            val = newVal
            // 通知所有订阅者
            dep.notify()
        }
    })
订阅者watcher.js关联着模板编译,每个生成的订阅者都包含一个修改模板的callback,一旦对应发布者Observer.js中的set函数执行,所有对应订阅者接收到通知,就会执行该订阅者被创建时包含的callback,修改视图。
    update: function(){
        this.run() // 属性值变化收到通知
    },
    run: function(){
        // 数据改变时
        var value = this.vm.data[this.exp] // 取到最新的值 || this.get()
        var oldVal = this.value // 存储老值
        if(value !== oldVal){
            this.value = value
            this.cb.call(this.vm,value,oldVal) // 执行compile中的回调,更新视图
        }
    }
在Vue中实现数据绑定有两种途径,一种是双大括号{{}},一种是v-model,为了将数据绑定到页面,同时为了给包含这两种情况的模板添加订阅者,编写compile.js来实现。compile.js接收MVVM实例中挂载的根节点和该实例对象。先将所有节点剪切到fragment文档片段中,再通过遍历所有节点的方式,碰到包含数据绑定的节点,就创建一个新的watcher,并包含改变视图的callback从而与watcher.js关联,碰到其他类似事件绑定的节点,则给其绑定事件监听器,从而实现v-on的事件绑定效果。另外使用文档片段的好处是避免了页面的频繁的回流重绘,文档节点使用完毕后返回页面只需渲染一次即可。

核心代码

    init(){
        if(this.el){
            this.fragment = this.nodeToFragment(this.el) 
            this.compileElement(this.fragment);
            this.el.appendChild(this.fragment);
        }
    },
    // 节点全部转为文档片段
    nodeToFragment(el){
        // 创建空的文档片段
        var fragment = document.createDocumentFragment()
        var child = el.firstChild
        while(child){
            // 子节点推入文档片段,appendChild会有剪切的效果!!!!!
            fragment.appendChild(child)
            child = el.firstChild
        }
        return fragment
    },
    compileElement(el){
        // 创建好的文档片段拿过来编译
        var childNodes = el.childNodes
        var self = this
        // dom数组不是真正的数组,没有遍历方法

        // 多层嵌套slice处理效率过低导致执行失效
        // [].slice.call(childNodes).forEach(function(node){})
        // 也好像不是????在控制台测试了一下都运行的飞快啊...
        Array.prototype.forEach.call(childNodes,function(node){
            // 处理{{}}的正则
            var reg = /\{\{(.*)\}\}/
            var text = node.textContent

            if(self.isElementNode(node)){
                self.compile(node)
            }else if(self.isTextNode(node) && reg.test(text)){
                // 检测到双括号
                self.compileText(node,reg.exec(text)[1])
            }

            // 递归编译,编译所有节点
            if(node.childNodes && node.childNodes.length){
                self.compileElement(node)
            }
        })
    }

参考链接

canfoo

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

推荐阅读更多精彩内容