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 ...
随机推荐
- HTML5与CSS3权威指南.pdf2
第三章 HTML5的结构 article元素更强调独立性,section元素强调分段,div元素强调css的套用,aretcle元素和section元素在核实的情况下可以调换 nav元素用作页面导航的 ...
- JavaScript高级程序设计46.pdf
鼠标按钮 只有在主鼠标按钮被单击(或键盘回车键被按下)是才会触发click事件,对于mousedown和mouseup事件,其event对象存在一个button属性,表示按下或者释放按钮.DOM的bu ...
- (DT系列一)DTS结构及其编译方法
DTS结构及其编译方法 一:主要问题 1,需要了解dtsi与dts的关系 2,dts的结构模型 3,dts是如何被编译的,以及编译后会生成一个什么文件. 二:参考文字 1,DTS(device tre ...
- linux下如何执行PHP脚本
Linux 下如何直接执行 php 脚本? 下面是部分 php 命令行参数. 用法 php [-q] [-h] [-s] [-v] [-i] [-f ] | { [args...]} -q 安静模式, ...
- [学习笔记]设计模式之Abstract Factory
写在前面 为方便读者,本文已添加至索引: 设计模式 学习笔记索引 在上篇笔记Builder设计模式中,时の魔导士祭出了自己的WorldCreator.尽管它因此能创造出一个有山有树有房子的世界,但是白 ...
- Oracle的OFA架构
最优灵活体系结构(Optimal Flexible Architecture,简称OFA) OFA其实就是一种Oracle的一种规范,其意义就是用一种统一的给文件和文件夹的规则,和文件存放目录的规则做 ...
- Android 开发60条技术经验总结(转)
Android 开发60条技术经验总结: 1. 全部Activity可继承自BaseActivity,便于统一风格与处理公共事件,构建对话框统一构建器的建立,万一需要整体变动,一处修改到处有效. 2. ...
- mybatis update语句参数正常, 数据没有更新
昨天做的一个功能, 更新每天支付宝账号的所有订单收益 ,有一个update 语句:
- Excel中如何查找并列出所有链接(外部数据链接)?
在 Excel 中,有时会需要创建外部链接来引用其他工作簿的单元格内容,但是如果想要找出所有链接并且还要将这些外部数据链接列在一个工作簿当中是有点难度的.下面我会介绍一些快捷方法,不仅能够快速帮你找出 ...
- 统计功能和子对象的大小信息查询Bug
I hava below two statement sql: 0. not in subquery select a.schemaname, pg_size_pretty(pg_total_rela ...