Javascript实现angularjs的MVC

原文地址

转自: http://www.cnblogs.com/front-end-ralph/p/5190442.html
学习了这篇文章,自己敲了几行代码验证,作为记录,尊重原创的作者

我的记录

Demo1

MVC框架,在前端中,我们用html作为View,因此此处只需关注model 和 controller即可。首先定义一下Model

function Model(value){
    //如果value没有定义,则设置为0
    this._value = typeof value ==='undefined'?"":value;
    //_listeners保存了监听该module的回调函数
    this._listeners =[];
}

为了简化Model, 我们假设Model中只有一个value的值需要被订阅(观察者模式)。this._listeners中保存了所有的观察者的回调函数。
接下来,需要编写一个修改 value值的函数

//Model的set函数
Model.prototype.set=function(value){
    var self = this;
    self._value = value;
    //set函数会改变model的value值,因此需要通知监听model的函数
    //按照Javascript事件处理的一般机制,采用异步调用回调函数
    setTimeout(function(){
        self._listeners.forEach(function(listener){
            listener.call(self,value);
        })
    })
};

set函数会修改model的value值,在该值被修改之后,异步调用观察者队列中的回调函数,将新的value作为参数传入回调函数中。
那么还有一个问题, 如何为model添加观察者? 那就再编写一个函数用来添加model

//Model的watch函数
Model.prototype.watch=function(listener){
    this._listeners.push(listener);
}

第一步完成,接下来如何使用这个model。如下:

(function(){
    //首先new一个model
    var model = new Model();
    var div1 = document.getElementById("div1");
    //调用model的watch函数,开始监听model的value变化,并在值变化时,修改div的innerHTML
    model.watch(function(value){
        div1.innerHTML = value;
    });
    //当model的set函数被执行,watch中的函数会被异步调用,设置 div的innerHTML
    model.set("hello,this is a div");
})()

完整代码:

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
    <title>Javascript实现MVC(1)</title>
</head>
<script>
function Model(value){
    //如果value没有定义,则设置为0
    this._value = typeof value ==='undefined'?"":value;
    //_listeners保存了监听该module的回调函数
    this._listeners =[];
}
//Model的set函数
Model.prototype.set=function(value){
    var self = this;
    self._value = value;
    //set函数会改变model的value值,因此需要通知监听model的函数
    //按照Javascript事件处理的一般机制,采用异步调用回调函数
    setTimeout(function(){
        self._listeners.forEach(function(listener){
            listener.call(self,value);
        })
    })
};
//Model的watch函数
Model.prototype.watch=function(listener){
    this._listeners.push(listener);
}
</script>
<body>
    <div id="div1"></div>
</body>
<script>

//测试代码
(function(){
    var model = new Model();
    var div1 = document.getElementById("div1");
    //调用model的watch函数,开始监听model的value变化
    model.watch(function(value){
        div1.innerHTML = value;
    });
    //当model的set函数被执行,watch中的函数会被异步调用,设置 div的innerHTML
    model.set("hello,this is a div");
})()
</script>
</html>

运行结果:

hello,this is a div

Demo2

在Demo1的基础上,感觉watch函数太底层,希望对watch函数做一层封装。继续在model上添加一个bind函数

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

那么我们在使用时就更简单了,只需要在model的bind中传入监听的node, 在model的value改变时,node的innerHTML就会被改变

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

完整的代码如下:

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
    <title>Javascript实现MVC(2)</title>
</head>
<script>
function Model(value){
    //如果value没有定义,则设置为0
    this._value = typeof value ==='undefined'?"":value;
    //_listeners保存了监听该module的回调函数
    this._listeners =[];
}
//Model的set函数
Model.prototype.set=function(value){
    var self = this;
    self._value = value;
    //set函数会改变model的value值,因此需要通知监听model的函数
    //按照Javascript事件处理的一般机制,采用异步调用回调函数
    setTimeout(function(){
        self._listeners.forEach(function(listener){
            listener.call(self,value);
        })
    })
};
//Model的watch函数
Model.prototype.watch=function(listener){
    this._listeners.push(listener);
}

Model.prototype.bind=function(node){
    //将watch的逻辑和通用的回调函数放这里
    this.watch(function(value){
        node.innerHTML = value;
    })
}
</script>
<body>
    <div id="div1"></div>
    <div id="div2"></div>
</body>
<script>

//测试代码
(function(){
    var model = new Model();
    model.bind(document.getElementById("div1"));
    model.bind(document.getElementById("div2"));
    model.set("this is a div ");
})()
</script>
</html>

运行结果:

this is a div
this is a div

Demo3

demo1 和 demo2 都只设计了model,并没有讲到 controller 。
我们现在不想要自己手动在js代码中绑定bind, 想要通过在html上的属性bind就自动绑定到一个model。 为了实现这样的功能,我们定义一个controller

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);
}

这个controller会帮我们将html上的bind属性自动绑定到一个model上,而且controller会自动帮我们调用一次自定义的回调函数callback,因此我们只需要在callback中写入业务逻辑代码即可。

//测试代码1
new Controller(function (models) {
    var model = models.myModel;
    model.set('this is a div');
});

如上代码所示,我们的业务逻辑代码是想要修改绑定了myModel这个model的div的值。
完整代码:

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
    <title>Javascript实现MVC(2)</title>
</head>
<script>
function Model(value){
    //如果value没有定义,则设置为0
    this._value = typeof value ==='undefined'?"":value;
    //_listeners保存了监听该module的回调函数
    this._listeners =[];
}
//Model的set函数
Model.prototype.set=function(value){
    var self = this;
    self._value = value;
    //set函数会改变model的value值,因此需要通知监听model的函数
    //按照Javascript事件处理的一般机制,采用异步调用回调函数
    setTimeout(function(){
        self._listeners.forEach(function(listener){
            listener.call(self,value);
        })
    })
};
//Model的watch函数
Model.prototype.watch=function(listener){
    this._listeners.push(listener);
}

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

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);
}
</script>
<body>
    <div id="div1" bind="myModel"></div>
    <div id="div2" bind="myModel"></div>
    <span bind="hour"></span> : <span bind="minute"></span> : <span bind="second"></span>
</body>
<script>
//测试代码1
new Controller(function (models) {
    var model = models.myModel;
    model.set('this is a div');
});
//测试代码2
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);
});
</script>
</html>

运行结果:

this is a div
this is a div
12 : 53 : 25
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值