mvc、mvvm及原生实现数据劫持和指令解析

Vue

vue是一套用于构建用户界面的渐进式框架(没有强主张,就是强制要求用了vue,就必须使用与vue相关的其他东西才可以进行项目的开发,我们可以任意组合),也是一个mvvm的框架,mvvm(model-view-viewmodel),就是通过数据(model)驱动视图(view),而视图的改变也可以修改数据,而负责视图和数据联系的就是viewmodel

使用javascrit操作html到目前总共经历了四个发展阶段

第一阶段

直接用javascript操作dom

var dom = document.getElementById('name');
dom.innerHTML = 'Homer';
dom.style.color = 'red';

第二阶段

由于原生API不好用,还要考虑浏览器兼容性,jQuery横空出世

$('#name').text('Homer').css('color', 'red');

第三阶段

mvc模式,MVC是Model-View- Controller的简写。即模型-视图-控制器。

Model(模型):是应用程序中用于处理应用程序数据逻辑的部分。通常模型对象负责在数据库中存取数据。

Model定义了这个模块的数据模型。
在代码中体现为数据管理者,Model负责对数据进行获取及存放。
数据不可能凭空生成的,要么是从服务器上面获取到的数据,要么是本地数据库中的数据,
也有可能是用户在UI上填写的表单即将上传到服务器上面存放,所以需要有数据来源。
既然Model是数据管理者,则自然由它来负责获取数据。

View(视图):简单来说,就是我们在界面上看见的一切,是应用程序中处理数据显示的部分。通常视图是依据模型数据创建的。

Controller(控制器):是应用程序中处理用户交互的部分。通常控制器负责从视图读取数据,控制用户输入,并向模型发送数据。

Controller是MVC中的数据和视图的协调者,也就是在Controller里面把Model的数据赋值给View来显示
(或者是View接收用户输入的数据然后由Controller把这些数据传给Model来保存到本地或者上传到
服务器)。

综合以上内容,我们所有的App都是界面和数据的交互,所以需要类来进行界面的绘制,于是出现了View,需要类来管理数据于是出现了Model。我们设计的View应该能显示任意的内容比如页面中显示的文字应该是任意的而不只是某个特定Model的内容,所以我们不应该在View的实现中去写和Model相关的任何代码,如果这样做了,那么View的可扩展性就相当低了。而Model只是负责处理数据的,它根本不知道数据到时候会拿去干什么,它既然无法接收用户的交互,它就不应该去管和视图相关的任何信息,所以Model中不应该写任何View相关代码。然而我们的数据和界面应该同步,也就是一定要有个地方要把Model的数据赋值给View,而Model内部和View的内部都不可能去写这样的代码,所以只能新创造一个类出来了,取名为Controller

第四阶段

mvvm模式

mvvm(model-view-viewmodel),model和view的定义同mvc中的mv是一致的,而viewmodel就是对mvc中c这部分功能的抽离,在实际编程中,m负责拿到数据,v负责视图,这两个已经的固定的了,但是我们发现在c中,我们除了控制交互外,我们进行了大量的数据分析,当页面越复杂,c越臃肿,然而c的设计初衷是:1、管理自己的生命周期;2、处理Controller之间的跳转;3、实现Controller容器。从设计初衷我们就可以看到,c的设计根本没有数据分析这一块,那么数据分析该由谁来做?这就是viewmodel产生的原因,专门用于数据分析处理

为什么不叫mvcvm呢?c只是被弱化了,并不是不存在,c的存在更加单纯和纯粹,它充当一个处理器,来进行各部分的协调运作,相当于一个隐藏的幕后推手,它只关心结果,而vm则负责接手c的数据分析处理的工作

// 数据劫持
function observe(data) {
    if(!data || typeof data !== 'object') {
        return;
    }
    Object.keys(data).forEach(key => {
        observeProperty(data, key, data[key]);
    })
}

function observeProperty(obj, key, val) {
    observe(val);
    Object.defineProperty(obj, key, {
        enumerable: true,
        configurable: true,
        get: function() {
            return val;
        },
        set: function(newVal) {
            if(val === newVal) {
                return;
            }
            console.log('数据更新啦', val, '->', newVal);
            val = newVal;
        }
    })
}
// 指令解析
class Compile {
    constructor(el, vm) {
        this.$vm = vm;
        this.$el = this.isElementNode(el) ? el : document.querySelector(el);
        if(this.$el) {
            this.compileElement(this.$el);
        }
    }
    compileElement(el) {
        let _this = this;
        let childNodes = el.childNodes;
        [...childNodes].forEach(item => {
            let text = item.textContent;
            let reg = /\{\{((?:.|\n)+?)\}\}/;
            if(_this.isElementNode(item)) {
                _this.compile(item);
            }
            else if(_this.isTextNode(item) && reg.test(text)) {
                _this.compileText(item, RegExp.$1.trim());
            }

            if(item.childNodes && item.childNodes.length > 0) {
                _this.compileElement(item);
            }
        })
    }

    compile(node) {
        let nodeAttrs = node.attributes;
        [...nodeAttrs].forEach(item => {
            let attrName = item.name;
            if(this.isDeractive(attrName)) {
                let value = item.value;
                node.innerHTML = typeof this.$vm[value] === 'undefined' ? '' : this.$vm[value];
                node.removeAttribute(attrName);
            }
        })
    }

    compileText(node, val) {
        node.textContent = typeof this.$vm[val] === 'undefined' ? '' : this.$vm[val];
    }

    isElementNode(node) {
        return node.nodeType === 1;
    }

    isTextNode(node) {
        return node.nodeType === 3;
    }

    isDeractive(attr) {
        return attr.indexOf('k-') === 0;
    }

}

你可能感兴趣的:(mvc、mvvm及原生实现数据劫持和指令解析)