前段时间一直在想前端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. (转载)VC/MFC 工具栏上动态添加组合框等控件的方法

    引言 工具条作为大多数标准的Windows应用程序的 一个重要组成部分,使其成为促进人机界面友好的一个重要工具.通过工具条极大方便了用户对程序的操作,但是在由Microsoft Visual C++开 ...

  2. Bzoj 1674: [Usaco2005]Part Acquisition dijkstra,堆

    1674: [Usaco2005]Part Acquisition Time Limit: 5 Sec  Memory Limit: 64 MBSubmit: 337  Solved: 162[Sub ...

  3. eclipse 反编译class 文件 插件-jad

    1.下载 jad.exe  http://pan.baidu.com/s/1i3Ga33n 2.下载jadeclipse http://pan.baidu.com/s/1bn4H1iZ  放在ecli ...

  4. UILabel字体加粗等属性和特效

    /* Accessing the Text Attributes text  property font  property textColor  property textAlignment  pr ...

  5. [置顶] 深入理解android之IPC机制与Binder框架

    [android之IPC机制与Binder框架] [Binder框架.Parcel.Proxy-Stub以及AIDL] Abstract [每个平台都会有自己一套跨进程的IPC机制,让不同进程里的两个 ...

  6. Javascript类型——boolean类型

    布尔值在Javascript中有两个值:true和false. 布尔值和其他数据类型的转换关系 数据类型 true false boolean true false String 任何非空字符串 &q ...

  7. ios 实现跳转到评价界面的两种方式

    要想在App内跳转到特定App的详情页或者评论页,首先需要获取到App的id.在 iTunes Connect网站上登陆之后,选择“我的App”,然后点击某个特定的App进入,在App信息的综合信息中 ...

  8. [ORACLE]数据库之间复制表

    ---------------------------------------------------------------------------- -------------ORACLE数据库管 ...

  9. 使用tuple返回多个值

    17.4编写并测试findbook函数 #include<iostream> #include<vector> #include<string> #include& ...

  10. OC学习笔记[注意事项]

    alloc  new  retain之后都必须要调用release方法 计数器要变只有这几种方法 retain release alloc new copy方法才会使计数器改变,谁想用人家对象,就对他 ...