前段时间一直在想前端MVC的意义。这个话题仁者见仁,但是MVC的使用方法给我提了一个管理数据的有意思的想法--数据管理和数据驱动页面。我们以前的思路一直是事件驱动页面,事件驱动页面合乎逻辑而且节约代码。但是往往代码组织结构非常松散,这个松散并不是大家所期望的松耦合,而是一种乱七八糟的感觉,后来在一次code中,我尝试了一下用数据来驱动页面,觉得效果也不错,逻辑也比较简单。下面简单分享一下我的思路。

  1. 我有一个电子商店,我需要一个购物车功能。
  2. 我希望购物车能在前端处理相关逻辑。而后台只是保存用户订单。

下面是订单保存的数据格式。

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 中的数据驱动页面模式的更多相关文章

  1. Javascript中理解发布--订阅模式

    Javascript中理解发布--订阅模式 阅读目录 发布订阅模式介绍 如何实现发布--订阅模式? 发布---订阅模式的代码封装 如何取消订阅事件? 全局--发布订阅对象代码封装 理解模块间通信 回到 ...

  2. 【转】Javascript中理解发布--订阅模式

    Javascript中理解发布--订阅模式 阅读目录 发布订阅模式介绍 发布---订阅模式又叫观察者模式,它定义了对象间的一种一对多的关系,让多个观察者对象同时监听某一个主题对象,当一个对象发生改变时 ...

  3. JavaScript中让Html页面中循环播放文字

    JavaScript中让Html页面中循环播放文字 <html> <head> <meta http-equiv="Content-Type" con ...

  4. js架构设计模式——理解javascript中的MVVM开发模式

    理解javascript中的MVVM开发模式 http://blog.csdn.net/slalx/article/details/7856769 MVVM的全称是Model View ViewMod ...

  5. JavaScript中的文档模式和严格模式

    JavaScript中的文档模式和严格模式 语法模式有普通模式和严格模式两种 普通模式:正常的JavaScript语法拼写以及代码编写(相对于严格模式存在着语法上的不严谨),尽可能的识别错误以及不规范 ...

  6. javascript中的发布订阅模式与观察者模式

    这里了解一下JavaScript中的发布订阅模式和观察者模式,观察者模式是24种基础设计模式之一. 设计模式的背景 设计模式并非是软件开发的专业术语,实际上设计模式最早诞生于建筑学. 设计模式的定义是 ...

  7. [转] Javascript中理解发布--订阅模式

    发布订阅模式介绍 发布---订阅模式又叫观察者模式,它定义了对象间的一种一对多的关系,让多个观察者对象同时监听某一个主题对象,当一个对象发生改变时,所有依赖于它的对象都将得到通知. 现实生活中的发布- ...

  8. JavaScript 中的延迟加载属性模式

    传统上,开发人员在 JavaScript 类中为实例中可能需要的任何数据创建属性.对于在构造函数中随时可用的小块数据来说,这不是问题.但是,如果在实例中可用之前需要计算某些数据,您可能不想预先支付该费 ...

  9. typeof操作符在javascript中运用时时页面上的操作数显示

    typeof可以告诉我们它的操作数是一个字符串(string).数值(number).函数(function).布尔值(boolean)或对象(object). 1.字符串(string) alert ...

随机推荐

  1. poj 2932 Coneology(扫描线+set)

    Coneology Time Limit: 5000MS   Memory Limit: 65536K Total Submissions: 3574   Accepted: 680 Descript ...

  2. HDU 4786 Fibonacci Tree (2013成都1006题) 最小生成树+斐波那契

    题意:问生成树里能不能有符合菲波那切数的白边数量 思路:白边 黑边各优先排序求最小生成树,并统计白边在两种情况下数目,最后判断这个区间就可以.注意最初不连通就不行. #include <stdi ...

  3. Axure原型用pmdaniu在线托管尝试

    这次把原型中语音模块的坑填了一部分,实现了拖拽按钮控制的界面效果 http://www.pmdaniu.com/prototype/view?id=WXpVNwNhUmYMPFN3AkA

  4. The File's Owner

    The File Owner is an instantiated, runtime object that owns the contents of your nib and its outlets ...

  5. 【python自动化第五篇:python入门进阶】

    今天内容: 模块的定义 导入方法 import的本质 导入优化 模块分类 模块介绍 一.模块定义: 用来在逻辑上组织python代码(变量,函数,逻辑,类):本质就是为了实现一个功能(就是以.py结尾 ...

  6. 运用HBuilder上传到GitHub

    Hbuilder安装github插件 如图所示: 一.打开自己GitHub,新建一个"库" 2.设置自己项目名和简介 3.建完后,就会显示GitHub要上传路径 4.打开" ...

  7. 新安装XAMPP,phpMyAdmin错误:#1045 - Access denied for user 'root'@'localhost' (using password: NO)

    错误如下: 打开D:\Program Files\xampp\phpMyAdmin(你的xampp的安装目录下的phpMyAdmin目录)目录下的config.inc.php文件 将 改为 然后,错误 ...

  8. Linux防火墙iptables学习笔记(三)iptables命令详解和举例[转载]

     Linux防火墙iptables学习笔记(三)iptables命令详解和举例 2008-10-16 23:45:46 转载 网上看到这个配置讲解得还比较易懂,就转过来了,大家一起看下,希望对您工作能 ...

  9. 模板引擎 Velocity

    模板引擎 Velocity 一.Velocity简介: Velocity是一个基于java的模板引擎(template engine).它允许任何人仅仅简单的使用模板语言(template langu ...

  10. 再谈内存管理与ARC运行机制(一)

    内存管理 内存在Objective-C开发中是一种相对稀缺的资源,拿Iphone4为例,它的内存只有512mb,所以妥善的处理好所创造,所使用的每个对象与变量都将成为一个问题.在ARC出现以前,同大部 ...