深入学习前端MVC和MVVM(二)

上一节说了后台的MVC,现在开始讲重点,前端的MVC又是一个什么鬼。
很长一段时间我都没有搞清楚MVC和MVVM。
一直在说ng是MVC,react和Vue是MVVM,MVVM我用过了,用过vue和react,他们的数据绑定,那么MVC究竟是什么样子呢?

一个简单MVC的实现

有一篇很好的文章讲了MVC:
http://www.imooc.com/article/4911

重点:
MVC的基础是观察者模式;
这里还有一个问题,就是MVC为什么不是23种设计模式中的一种呢?
在网上找了很多答案:
说MVC每一个M、V、C都是一种模式,即观察者模式、策略模式、组合模式的结合;

第一步:先实现model来看看

这里我们先看Model.js

//实际上这里是一个观察者模式

function Model(value) {
    this._value = typeof value === 'undefined' ? '' : value;
    this._listeners = [];
}

Model.prototype.set = function (value) {
    var self = this;
    self._value = value;
    console.log(value);
    // model中的值改变时,应通知注册过的回调函数
    // 按照Javascript事件处理的一般机制,我们异步地调用回调函数
    // 如果觉得setTimeout影响性能,也可以采用requestAnimationFrame
    setTimeout(function () {
        self._listeners.forEach(function (listener) {
            listener.call(self, value);
        });
    });
};
Model.prototype.watch = function (listener) {
    // 注册监听的回调函数
    console.log(listener);
    this._listeners.push(listener);
};
<div id="div1"></div>
<script src="./model.js"></script>
<script>
// 逻辑代码:
(function() {
    var model = new Model();
    var div1 = document.getElementById('div1');
    var setValue=function (value) {
        div1.innerHTML=value;
    }
    // model.watch(function(value) {
    //     div1.innerHTML = value;
    // });
    model.watch(setValue)
    model.set('hello, this is a div');
    model.set('hello, this is a div2');

})();
</script>

上面代码的调用是这样的:提供了一个监听方法,Model.prototype.wacth,在实例中,监听的就是setValue这个方法,(我把原来代码里面的匿名函数注释掉了,因为这样便于理解)
监听事件列队插入 listener;
这里事实上我们并没有执行直接通过setValue(‘hello, this is a div’)执行,而是调用model的set方法执行的setValue(‘hello, this is a div’)

在model的set方法中,是遍历监听的事件。并将传给set的值,传给listener中的每一个事件。

比如我们稍微改一下:

/*view*/
<div id="div1"></div>
<div id="div2"></div>

<script src="./model.js"></script>
<script>
// 逻辑代码:
(function() {
    var model = new Model();
    var div1 = document.getElementById('div1');
    var div2 = document.getElementById('div2');

    var setValue=function (value) {
        div1.innerHTML=value;
    }
    var setValue2=function (value) {
        div2.innerHTML=value;
    }

    model.watch(setValue)
    model.watch(setValue2)
    model.set('hello, this is a div2');

})();
</script>

上面的代码model监听了两个事件,为div1和div2设值的setValue()和setValue2()
这里只调用了一次set方法,但是这两个setValue都执行了。

借助观察者模式,我们已经实现了在调用model的set方法改变其值的时候,模板也同步更新,但这样的实现却很别扭,因为我们需要手动监听model值的改变(通过watch方法)并传入一个回调函数,有没有办法让view(一个或多个dom node)和model更简单的绑定呢?

进一步,改进model,分离model和view的业务

上面的代码中view层还是有写setValue函数,不符合view的逻辑,view应该是看不到内部的操作。因此通过bind的方式实现setValue

 var setValue=function (value) {
        div1.innerHTML=value;
    }

通过bind的方式实现,在model.js中加上

Model.prototype.bind = function (node) {
    // 将watch的逻辑和通用的回调函数放到这里
    this.watch(function (value) {
        node.innerHTML = value;
    });
};

这个时候view的写法:
就只是看到节点绑定到了model上,以及设置节点的值。

(function () {
    var model = new Model();
    model.bind(document.getElementById('div1'));
    model.bind(document.getElementById('div2'));
    model.set('this is a div');
})();

最后一步:controller

这里一直只提到了MV,并没有C,其实controller是一种看不见的方式在运作

这里是controller.js的代码:

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

view层,实际上controller层完成了view和model的绑定。

<div id="div1" view="model1"></div>
<div id="div2" view="model2"></div>

new Controller(function (models) {
    console.log(models);
    var model1 = models.model1;
    model1.set('this is a div');
});
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值