javascript 中的数据驱动页面模式
前段时间一直在想前端MVC的意义。这个话题仁者见仁,但是MVC的使用方法给我提了一个管理数据的有意思的想法--数据管理和数据驱动页面。我们以前的思路一直是事件驱动页面,事件驱动页面合乎逻辑而且节约代码。但是往往代码组织结构非常松散,这个松散并不是大家所期望的松耦合,而是一种乱七八糟的感觉,后来在一次code中,我尝试了一下用数据来驱动页面,觉得效果也不错,逻辑也比较简单。下面简单分享一下我的思路。
- 我有一个电子商店,我需要一个购物车功能。
- 我希望购物车能在前端处理相关逻辑。而后台只是保存用户订单。
下面是订单保存的数据格式。
var orderList = {
0:{
'id':'12653',
'productName':'Kindle fire',
'price':790,
'amount':2,
'discount':0.75
},
1:{
'id':'2653',
'productName':'iPad',
'price':2790,
'amount':10,
'discount':0.70
},
2:{
'id':'653',
'productName':'Mac',
'price':7900,
'amount':1,
'discount':0.95
},
length:3,
subscriberId:'254',
totalPrice:0
}
首先我们使用一个数据管理器来维护用户的订单数据,我们把它设计为一个单体模式。
var shppingCar = function() {
var orderList = {}
this.add = function(obj){
//添加一条购买数据
}
this.remove = function(obj){
//删除一条购买数据
}
this.getTotilPrice = function(obj){
//获取总价
}
this.update = function(obj){
//更新购买数量
}
this.getOrder = function(){
return orderList;
}
}
这看起来数据结构清晰,代码组织似乎也不错。接下来涉及到我们DOM部分的操作了。
var order = new shppingCar();
orderList = order.getOrder();
var htmlManager = function(list){
//用orderList数据渲染页面。
}
//第一次初始化数据
htmlManager();
//添加一条数据
orderList.add({});
orderList = order.getOrder();
htmlManager(orderList);
//删除一条数据
orderList.add(id);
orderList = order.getOrder();
htmlManager(orderList);
//更新一条数据
orderList.update(id);
orderList = order.getOrder();
htmlManager(orderList);
每做一次数据操作,我们都要更新一次数据。我们没有办法改变这个事实,因为事实就是数据改变,我们必然要修改页面。
或许你有更好的办法,那就是不用orderList渲染DOM,而是用一个回调函数来处理。那么代码变为
this.add = function(obj,fn){
//添加一条购买数据
if(fn){
fn();
}
}
你可以这样使用
orderList.add({},function(){
//解析一次数据,生成一条DOM结构,插入
//更改总价
});
这样也意味着你分别要为删除、添加、更新书写不同的回调函数,看起来也并不是一个非常好的办法。
回到前面的代码,我们只需要做一个小小的改变,就可以用数据的改变来驱动我们的页面更新,这也是一个伪观察者模式。其思想就是:数据更新了,我要重新渲染页面。
var shppingCar = function() {
var orderList = {}
//我们给shppingCar添加了一个私有方法,当数据改变时自动为我们来更新页面。
var rander = function(){
}
this.add = function(obj){
//添加一条购买数据
rander();
}
this.remove = function(obj){
//删除一条购买数据
rander();
}
this.getTotilPrice = function(obj){
//获取总价
rander();
}
this.update = function(obj){
//更新购买数量
rander();
}
this.getOrder = function(){
return orderList;
}
}
这样我们使用的时候,就可以这样了
var orderList = new shppingCar();
//添加一条数据
orderList.add({});
我们只是把外部渲染函数改成了购物车对象的私有方法,然后在数据变动时调用这个私有方法,就可以省去了在外部每次更新数据都要再次调用一个更新页面的方法。虽然代码量减少的不是很多,但是将所有的内容封装起来外面调用看起来更是省心省力。
至于删除数据和更新数据,我们甚至不需要在外部定义,直接在渲染页面的时候把事件绑定到元素之后即可(下面的示例代码我实现了一个删除绑定,修改商品个数的功能大家有兴趣可以自己实现。)
我不知道这样做是否有意义,希望大家拍。
附测试代码如下。
var shppingCar = function() {
//我们把数据设计为这样的格式
var orderList = {
length:0,
subscriberId:'254',
totalPrice:0
}
//一些工具方法
//通过图书id获取当前是第几条数据
var getItemById = function(id){
for (var i = 0; i < orderList.length; i++) {
if(orderList[i].id == id) {
return i;
}
}
}
//重新整理数据成为标准格式
var refreshData = function(){
var o = {},n = [];
for (var key in orderList) {
var k = Number(key);
if(!isNaN(k)){
n.push(orderList[key]);
}else{
o[key] = orderList[key];
}
}
for (var i = 0; i < n.length; i++) {
o[i] = n[i];
}
orderList = o;
}
//计算总价
var updateTotilPrice = function() {
var totalprice = 0;
for (var i = 0; i < orderList.length; i++) {
totalprice +=orderList[i].price*orderList[i].discount*orderList[i].amount;
}
return totalprice;
};
//渲染页面
var htmlManager = function () {
var items = "<ul>";
for (var i=0;i<orderList.length;i++) {
items += "<li><span>商品编号:"+orderList[i].id
+"</span> <span>商品名字:"+orderList[i].productName
+"</span> <span>商品价格:"+orderList[i].price
+"</span> <span>订购数量:"+orderList[i].amount
+"</span> <span>商品折扣:"+orderList[i].discount+"</span>"
+"<a data-id="+orderList[i].id+" href='###'>删除</a></li>"
}
items += "</ul>";
items+="商品总价格为"+ orderList.totalPrice +"元";
document.getElementsByTagName("body")[0].innerHTML = (items);
//绑定删除事件
var delBtns = document.getElementsByTagName("a");
for (var j = 0; j < delBtns.length; j++) {
(function(k){
delBtns[k].onclick = function(){
remove(delBtns[k].getAttribute('data-id'));
return false;
}
})(j)
}
//绑定修改个数事件
};
//删除一条数据
var remove = function(id){
var item = getItemById(id);
delete orderList[item];
orderList.length-=1;
refreshData();
orderList.totalPrice = updateTotilPrice();
htmlManager();
}
//更新商品个数
var update = function(id,amount){
//TODO:更新购买数量
orderList.totalPrice = updateTotilPrice();
htmlManager();
}
//对外俩个接口方法,一个可以添加一条购买数据,一个为获取当前购物车的所有数据
this.add = function(obj){
//TODO:验证传入的数据是否合法
//TODO:此处判断是否已经存在该商品,如果存在,则调用updata方法。
orderList[orderList.length] = obj;
if(orderList[orderList.length]){
orderList.length +=1;
}
orderList.totalPrice = updateTotilPrice();
htmlManager();
}
this.getOrder = function() {
return orderList;
};
};
//使用方法:
var orderList = new shppingCar();
orderList.add({
'id':'6530',
'productName':'Mac mini-0',
'price':4900,
'amount':4,
'discount':0.90
})
orderList.add({
'id':'65301',
'productName':'Mac mini-1',
'price':5000,
'amount':4,
'discount':0.90
})
document.onclick = function() {
console.log(orderList.getOrder());
};
javascript 中的数据驱动页面模式的更多相关文章
- Javascript中理解发布--订阅模式
Javascript中理解发布--订阅模式 阅读目录 发布订阅模式介绍 如何实现发布--订阅模式? 发布---订阅模式的代码封装 如何取消订阅事件? 全局--发布订阅对象代码封装 理解模块间通信 回到 ...
- 【转】Javascript中理解发布--订阅模式
Javascript中理解发布--订阅模式 阅读目录 发布订阅模式介绍 发布---订阅模式又叫观察者模式,它定义了对象间的一种一对多的关系,让多个观察者对象同时监听某一个主题对象,当一个对象发生改变时 ...
- JavaScript中让Html页面中循环播放文字
JavaScript中让Html页面中循环播放文字 <html> <head> <meta http-equiv="Content-Type" con ...
- js架构设计模式——理解javascript中的MVVM开发模式
理解javascript中的MVVM开发模式 http://blog.csdn.net/slalx/article/details/7856769 MVVM的全称是Model View ViewMod ...
- JavaScript中的文档模式和严格模式
JavaScript中的文档模式和严格模式 语法模式有普通模式和严格模式两种 普通模式:正常的JavaScript语法拼写以及代码编写(相对于严格模式存在着语法上的不严谨),尽可能的识别错误以及不规范 ...
- javascript中的发布订阅模式与观察者模式
这里了解一下JavaScript中的发布订阅模式和观察者模式,观察者模式是24种基础设计模式之一. 设计模式的背景 设计模式并非是软件开发的专业术语,实际上设计模式最早诞生于建筑学. 设计模式的定义是 ...
- [转] Javascript中理解发布--订阅模式
发布订阅模式介绍 发布---订阅模式又叫观察者模式,它定义了对象间的一种一对多的关系,让多个观察者对象同时监听某一个主题对象,当一个对象发生改变时,所有依赖于它的对象都将得到通知. 现实生活中的发布- ...
- JavaScript 中的延迟加载属性模式
传统上,开发人员在 JavaScript 类中为实例中可能需要的任何数据创建属性.对于在构造函数中随时可用的小块数据来说,这不是问题.但是,如果在实例中可用之前需要计算某些数据,您可能不想预先支付该费 ...
- typeof操作符在javascript中运用时时页面上的操作数显示
typeof可以告诉我们它的操作数是一个字符串(string).数值(number).函数(function).布尔值(boolean)或对象(object). 1.字符串(string) alert ...
随机推荐
- html背景为灰色 不能操作,中间div可以操作
<container style="position: absolute; top: 0px; left: 0px; width: 0px; height: 0px; z-index: ...
- Java web.xml加载顺序
web.xml加载过程(步骤): 1.启动WEB项目的时候,容器(如:Tomcat)会去读它的配置文件web.xml.读两个节点: <listener></listener&g ...
- Using Live555 to Stream Live Video from an IP camera connected to an H264 encoder
http://stackoverflow.com/questions/27279161/using-live555-to-stream-live-video-from-an-ip-camera-con ...
- Oracle 字符集的查看和修改
Oracle字符集是一个字节数据的解释的符号集合,有大小之分,有相互的包容关系.ORACLE 支持国家语言的体系结构允许你使用本地化语言来存储,处理,检索数据.它使数据库工具,错误消息,排序次序,日期 ...
- iOS全景
一张鱼眼图或者6方图,展现出来的全景影像效果图 PanoramaGL PanoramaGL是世界上第一个开源的实现360度全景图像的iOS.Android类库.基于OpenGL 支持球,立方体,圆柱. ...
- 【转载】Storm TickTuple 意外停止
原文链接转自:http://woodding2008.iteye.com/blog/2328114 Storm的滑动窗口TickTuple通常用来控制bolt定制执行入库操作,使用过程中遇到了Tick ...
- Zend Framework 2参考Zend\Authentication(Zend\Authentication介绍)
原文:Zend Framework 2参考Zend\Authentication(Zend\Authentication介绍) Zend\Authentication组件提供了认证接口和具体的通用的认 ...
- tcpdump来抓取执行的sql语句
# tcpdump -n -nn -tttt -i eth1 -s 65535 'port 3306' -w tcpdump_mysql.ret -C 100 一个TCP包中包含多个mysql协议包, ...
- Linux主机安全配置的几个脚本【转载】
标签:linux Linux主机安全配置的几个脚本 职场 休闲原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 .作者信息和本声明.否则将追究法律责任.http://hx100.blog ...
- C# richTextBox编辑器
附件:http://files.cnblogs.com/xe2011/CSHARP_RichTextBoxEditor.rar 完整的转到这里 http://www.cnblogs.com/xe201 ...