美文网首页
简单实现前端MVC框架

简单实现前端MVC框架

作者: 齐修_qixiuss | 来源:发表于2016-02-25 12:10 被阅读694次

MVC/MVP/MVVM的区别

1. MVC

传统的MVC主要分为三部分
✦ View 传送指令到 Controller
✦ Controller 完成业务逻辑后,要求 Model 改变状态
✦ Model 将新的数据发送到 View,用户得到反馈

MVC通用架构

实际项目往往会更灵活,比如Backbone 索性取消了 Controller,只保留一个 Router(路由器) 。

2. MVP

MVP 模式将 Controller 改名为 Presenter,同时改变了通信方向。
✦ 各部分之间的通信,都是双向的。
✦ View 与 Model 不发生联系,都通过 Presenter 传递。
✦ View 非常薄,不部署任何业务逻辑,称为"被动视图"(Passive View),即没有任何主动性,而 Presenter非常厚,所有逻辑都部署在那里。

MVP架构图
3. MVVM

唯一的区别是,它采用双向绑定(data-binding):View的变动,自动反映在 ViewModel,反之亦然

MVVM架构图

实现model

01 初步
// Model 核心代码
function Model(value) {
    this._value = typeof value === 'undefined' ? '' : value;
    this._listeners = [];
}
Model.prototype.set = function(value) {
    var self = this;
    self._value = value;
    // model中的值改变时,应通知注册过的回调函数
    // 按照Javascript事件处理的一般机制,我们异步地调用回调函数
    // 如果觉得setTimeout影响性能,也可以采用requestAnimationFrame
    setTimeout(function() {
        self._listeners.forEach(function(listener) {
            listener.call(self, value);
        });
    });
};
Model.prototype.watch = function(listener) {
    // 注册监听的回调函数
    this._listeners.push(listener);
};
// html 代码:
<div id="div1"></div>

// 逻辑代码:
(function() {
    var model = new Model();
    var div1 = document.getElementById('div1');
    model.watch(function(value) {
        div1.innerHTML = value;
    });
    model.set('hello, this is a div');
})();
02 抽离中间方法,进一步简化
// 抽离中间方法
Model.prototype.bind = function(node) {
    // 将watch的逻辑和通用的回调函数放到这里
    this.watch(function(value) {
        node.innerHTML = value;
    });
};

// html代码:
<div id="div1"></div>
<div id="div2"></div>

// 逻辑代码:
(function() {
    var model = new Model();
    model.bind(document.getElementById('div1'));
    model.bind(document.getElementById('div2'));
    model.set('this is a div');
})();

实现controller

function Controller(callback) {
    var models = {};
    // 找到所有有bind属性的元素
    var views = document.querySelectorAll('[data-bind]');
    // 将views处理为普通数组
    views = Array.prototype.slice.call(views, 0);
    views.forEach(function(view) {
        var modelName = view.getAttribute('data-bind');
        // 取出或新建该元素所绑定的model
        models[modelName] = models[modelName] || new Model();
        // 完成该元素和指定model的绑定
        models[modelName].bind(view);
    });
    // 调用controller的具体逻辑,将models传入,方便业务处理
    callback.call(this, models);
}

// html:
<div id="div1" data-bind="model1"></div>
<div id="div2" data-bind="model1"></div>

// 逻辑代码:
new Controller(function (models) {
    var model1 = models.model1;
    model1.set('this is a div');
});

MVC完整版

function Model(value) {
    this._value = typeof value === 'undefined' ? '' : value;
    this._listeners = [];
}
Model.prototype.set = function(value) {
    var self = this;
    self._value = value;
    setTimeout(function() {
        self._listeners.forEach(function(listener) {
            listener.call(self, value);
        });
    });
};
Model.prototype.watch = function(listener) {
    this._listeners.push(listener);
};
Model.prototype.bind = function(node) {
    this.watch(function(value) {
        node.innerHTML = value;
    });
};

function Controller(callback) {
    var models = {};
    var views = Array.prototype.slice.call(document.querySelectorAll('[data-bind]'), 0);
    views.forEach(function(view) {
        var modelName = view.getAttribute('data-bind');
        (models[modelName] = models[modelName] || new Model()).bind(view);
    });
    callback.call(this, models);
}


// html:
<span data-bind="hour"></span> : <span data-bind="minute"></span> : <span bind="second"></span>

// controller:
new Controller(function (models) {
    function setTime() {
        var date = new Date();
        models.hour.set(date.getHours());
        models.minute.set(date.getMinutes());
        models.second.set(date.getSeconds());
    }
    setTime();
    setInterval(setTime, 1000);
});

相关文章

网友评论

      本文标题:简单实现前端MVC框架

      本文链接:https://www.haomeiwen.com/subject/xmbikttx.html