美文网首页
简单实现前端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