在介绍小项目之前,在此说明一下此代码并非本人所写,我只是随笔的整理者。

在介绍之前先展现一下效果图。

看过效果图大家应该很熟悉了,就是饿了么的一个界面而已,值得注意的是,实现时并没有采用本地连接,而是实打实的网络连接。看一下文件架构。

这一采用的是MVC设计模式,虽然文件很少,但是也可以看。

下面开始正式介绍小项目的实现。

首先介绍Model的实现,很简单,实现模型即可,

Shop.h

//
// Shop.h
// CX-小项目(饿了么 网络部分 简单实现)
//
// Created by ma c on 16/3/23.
// Copyright © 2016年 xubaoaichiyu. All rights reserved.
// #import <Foundation/Foundation.h> @interface Shop : NSObject
//建立Shop模型
@property (nonatomic, copy) NSString * address; @property (nonatomic, copy) NSString * name; @property (nonatomic, copy) NSString * image_path; //-description这个方法系统占用
@property (nonatomic, copy) NSString * desc; @end

Shop.m

//
// Shop.m
// CX-小项目(饿了么 网络部分 简单实现)
//
// Created by ma c on 16/3/23.
// Copyright © 2016年 xubaoaichiyu. All rights reserved.
// #import "Shop.h" @implementation Shop @end

model实现后我们并没有真正的实现方法,下面也不是,接下来是对AFN的封装,之所以封装是因为,我们难以保证在以后该三方还能存在,只要封装,哪怕以后没有了AFN我们也可以在封装框架里运用其他的三方实现。

HttpClient.h HttpClient.m

//
// HttpClient.h
// CX-小项目(饿了么 网络部分 简单实现)
//
// Created by ma c on 16/3/23.
// Copyright © 2016年 xubaoaichiyu. All rights reserved.
// #import <Foundation/Foundation.h>
#import "AFNetworking.h" //HTTP请求类别
typedef NS_ENUM(NSInteger,HttpRequestType) {
HttpRequestGet,
HttpRequestPost,
HttpRequestPut,
HttpRequestDelete,
}; /**
* 请求前预处理block
*/
typedef void(^PrepareExecuteBlock)(void); typedef void(^SuccessBlock)(NSURLSessionDataTask * task, id responseObject); typedef void(^FailureBlock)(NSURLSessionDataTask * task, NSError * error); @interface HttpClient : NSObject + (HttpClient *)defaultClient; /**
* HTTP请求(GET,POST,PUT,DELETE)
*
* @param url 请求地址
* @param method 请求类型
* @param params 请求参数
* @param prepare 请求前预处理
* @param success 请求成功处理
* @param failure 请求失败处理
*/ - (void)requestWithPath:(NSString *)url
method:(NSInteger)method
paramenters:(NSDictionary *)params
prepareExecute:(PrepareExecuteBlock)prepare
success:(SuccessBlock)success
failure:(FailureBlock)failure; @end
//
// HttpClient.m
// CX-小项目(饿了么 网络部分 简单实现)
//
// Created by ma c on 16/3/23.
// Copyright © 2016年 xubaoaichiyu. All rights reserved.
// #import "HttpClient.h" @interface HttpClient () @property (nonatomic, strong) AFHTTPSessionManager * manager; @property (nonatomic, assign) BOOL isConnect; @end @implementation HttpClient - (instancetype)init
{
self = [super init];
if (self) { self.manager = [AFHTTPSessionManager manager];
//设置请求类型
self.manager.requestSerializer = [AFHTTPRequestSerializer serializer];
//设置响应类型
self.manager.responseSerializer = [AFJSONResponseSerializer serializer]; self.manager.responseSerializer.acceptableContentTypes = [NSSet setWithObjects:@"application/json",@"text/html", @"text/json", @"text/javascript",@"text/plain",@"image/gif", nil]; //开启监听
[self openNetMonitoring]; }
return self;
}
//判断是否有网络连接,有网络连接再进行下一操作。
- (void)openNetMonitoring { [[AFNetworkReachabilityManager sharedManager] setReachabilityStatusChangeBlock:^(AFNetworkReachabilityStatus status) { switch (status) {
case AFNetworkReachabilityStatusUnknown:
self.isConnect = NO;
break;
case AFNetworkReachabilityStatusNotReachable:
self.isConnect = NO;
break;
case AFNetworkReachabilityStatusReachableViaWiFi:
self.isConnect = YES;
break;
case AFNetworkReachabilityStatusReachableViaWWAN:
self.isConnect = YES;
break;
default:
break;
} }]; [[AFNetworkReachabilityManager sharedManager] startMonitoring]; self.isConnect = YES;
}
//单例
+ (HttpClient *)defaultClient { static HttpClient * instance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
instance = [[self alloc] init];
});
return instance;
} - (void)requestWithPath:(NSString *)url
method:(NSInteger)method
paramenters:(NSDictionary *)params
prepareExecute:(PrepareExecuteBlock)prepare
success:(SuccessBlock)success
failure:(FailureBlock)failure { if ([self isConnectionAvailable]) { //预处理
if (prepare) {
prepare();
} switch (method) {
case HttpRequestGet:
[self.manager GET:url parameters:params progress:nil success:success failure:failure];
break;
case HttpRequestPost:
[self.manager POST:url parameters:params progress:nil success:success failure:failure];
break;
case HttpRequestPut:
[self.manager PUT:url parameters:params success:success failure:failure];
break;
case HttpRequestDelete:
[self.manager DELETE:url parameters:params success:success failure:failure];
break;
default:
break;
} } else { [self showExceptionDialog];
}
} - (BOOL)isConnectionAvailable { return self.isConnect;
}
//如果,没有网络,弹出Alert
- (void)showExceptionDialog { [[[UIAlertView alloc] initWithTitle:@"提示" message:@"网络连接异常,请检查网络连接" delegate:nil cancelButtonTitle:@"好的" otherButtonTitles: nil] show];
} @end

接下来是对SVProgressHUD进行封装

TollHeper.h TollHeper.m

//
// ToolHelper.h
// CX-小项目(饿了么 网络部分 简单实现)
//
// Created by ma c on 16/3/23.
// Copyright © 2016年 xubaoaichiyu. All rights reserved.
// #import <Foundation/Foundation.h> @interface ToolHelper : NSObject
/******************* 指示器方法 ****************/ //对指示器进行封装,如可出现新的主流三方,可以很好的给予升级 //弹出操作错误信息提示框
+ (void)showErrorMessage:(NSString *)message;
//弹出操作成功信息提示框
+ (void)showSuccessMessage:(NSString *)message;
//弹出加载提示框
+ (void)showProgressMessage:(NSString *)message;
//弹出用户信息
+ (void)showInfoMessage:(NSString *)message;
//取消弹出框
+ (void)dismissHUD;
@end
//
// ToolHelper.m
// CX-小项目(饿了么 网络部分 简单实现)
//
// Created by ma c on 16/3/23.
// Copyright © 2016年 xubaoaichiyu. All rights reserved.
// #import "ToolHelper.h"
#import "SVProgressHUD.h"
@implementation ToolHelper //弹出操作错误信息提示框
+ (void)showErrorMessage:(NSString *)message { [SVProgressHUD showErrorWithStatus:message]; }
//弹出操作成功信息提示框
+ (void)showSuccessMessage:(NSString *)message { [SVProgressHUD showSuccessWithStatus:message];
}
//弹出加载提示框
+ (void)showProgressMessage:(NSString *)message { [SVProgressHUD showWithStatus:message]; }
//弹出用户信息
+ (void)showInfoMessage:(NSString *)message { [SVProgressHUD showInfoWithStatus:message]; }
//取消弹出框
+ (void)dismissHUD { [SVProgressHUD dismiss];
} @end

做完以上工作之后下面需要解决的便是上面遗留下来的问题,不知道大家有没有发现在model里的注释

//-description这个方法系统占用

我们该怎么解决这个问题呢,那么我要说的便是三方啦。

MJ的三方解决了这一问题

MJExtensionConfig.h MJExtensionConfig.m

//
// MJExtensionConfig.h
// CX-小项目(饿了么 网络部分 简单实现)
//
// Created by ma c on 16/3/23.
// Copyright © 2016年 xubaoaichiyu. All rights reserved.
// #import <Foundation/Foundation.h> @interface MJExtensionConfig : NSObject @end
//
// MJExtensionConfig.m
// CX-小项目(饿了么 网络部分 简单实现)
//
// Created by ma c on 16/3/23.
// Copyright © 2016年 xubaoaichiyu. All rights reserved.
// #import "MJExtensionConfig.h"
#import "MJExtension.h"
#import "Shop.h" @implementation MJExtensionConfig //程序启动一定会调用
+ (void)load { /**
* 解决网络的JSON字段和本地模型属性名不一致的情况
*
* @return 左边是本地属性名,右侧是网络JSON名
*/ [Shop mj_setupReplacedKeyFromPropertyName:^NSDictionary *{ return @{@"desc" : @"description"};
}]; } @end

(对于load在前面的博客我有详细的解释,不清楚的朋友可以看看)

处理过后,为了方便对整个程序都能用到的便俩个 头文件进行优化,我们采用PCH文件

ELeMe.pch

//
// ELeMe.pch
// CX-小项目(饿了么 网络部分 简单实现)
//
// Created by ma c on 16/3/23.
// Copyright © 2016年 xubaoaichiyu. All rights reserved.
// #ifndef ELeMe_pch
#define ELeMe_pch #ifdef __OBJC__
#import <UIKit/UIKit.h>
#import <Foundation/Foundation.h>
#endif #import "ToolHelper.h" /***************SERVER HOST***************/ #define SERVER_HOST @"http://restapi.ele.me/v3" /***************SERVER API***************/ //获取餐馆列表
#define API_GetRestaurantsList @"/restaurants" #define SCREEN_WIDTH [UIScreen mainScreen].bounds.size.width #define SCREEN_HEIGHT [UIScreen mainScreen].bounds.size.height #define shopInfoPageLimit 20 #endif /* ELeMe_pch */

写完代码我们需要设置一下

设置如下

其实整个小项目真的很简单,导致并没有什么可以仔细去想的,写多了就好了。

下面是主要环节(注释说明的很详尽了,我就不多说废话了)

ViewController.h ViewController.m

//
// ViewController.h
// CX-小项目(饿了么 网络部分 简单实现)
//
// Created by ma c on 16/3/23.
// Copyright © 2016年 xubaoaichiyu. All rights reserved.
// #import <UIKit/UIKit.h> @interface ViewController : UIViewController @end
//
// ViewController.m
// CX-小项目(饿了么 网络部分 简单实现)
//
// Created by ma c on 16/3/23.
// Copyright © 2016年 xubaoaichiyu. All rights reserved.
// #import "ViewController.h"
#import "HttpClient.h"
#import "SVProgressHUD.h"
#import "Shop.h"
#import "MJExtension.h"
#import "ShopIconCell.h"
#import "MJRefresh.h" static NSString * identifier = @"ShopInfoCell"; @interface ViewController ()<UITableViewDataSource,UITableViewDelegate> //分页的页数
@property (nonatomic, assign) NSInteger page; @property (nonatomic, strong) UITableView * tableView; @property (nonatomic, strong) NSMutableArray * dataList; @end @implementation ViewController - (NSMutableArray *)dataList { if (!_dataList) {
_dataList = [NSMutableArray array];
}
return _dataList;
} - (UITableView *)tableView { if (!_tableView) {
_tableView = [[UITableView alloc] initWithFrame:self.view.bounds style:UITableViewStylePlain];
_tableView.dataSource =self;
_tableView.delegate =self;
[_tableView registerClass:[ShopInfoCell class] forCellReuseIdentifier:identifier];
_tableView.rowHeight = ;
}
return _tableView;
} - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return self.dataList.count;
} - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { ShopInfoCell * cell = [tableView dequeueReusableCellWithIdentifier:identifier]; cell.shop = self.dataList[indexPath.row]; return cell;
} - (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib. [self.view addSubview:self.tableView]; //使用MJRefresh给我们的talbleView添加下拉刷新上拉加载控件 self.tableView.mj_header = [MJRefreshNormalHeader headerWithRefreshingTarget:self refreshingAction:@selector(loadNewData)]; self.tableView.mj_footer = [MJRefreshBackNormalFooter footerWithRefreshingTarget:self refreshingAction:@selector(loadMoreData)]; // [self loadNewData]; //进入界面执行下拉刷新方法
[self.tableView.mj_header beginRefreshing]; } //上拉加载更多 - (void)loadMoreData { NSString * urlString = [NSString stringWithFormat:@"%@%@",SERVER_HOST,API_GetRestaurantsList]; NSDictionary * params = @{@"full_image_path":@"",
@"geohash":@"wx4u14w0649y",
@"limit":@(shopInfoPageLimit),
@"offset":@(self.page * shopInfoPageLimit),
@"type":@"geohash",
@"extras[]":@"food_activity",
@"extras[]":@"restaurant_activity"}; [[HttpClient defaultClient] requestWithPath:urlString method:HttpRequestGet paramenters:params prepareExecute:^{ [ToolHelper showProgressMessage:@"我在刷新"]; } success:^(NSURLSessionDataTask *task, id responseObject) {
NSLog(@"%@",responseObject); //JSON -> MODEL 有很多框架,原理都是KVC. //MJExtenstion JsonModel Mantle YYModel //请求的分页数据 +1 //当返回到数据的count值为0时,说明已经全部加载完毕。 NSArray * shopList = [Shop mj_objectArrayWithKeyValuesArray:responseObject]; // if (shopList.count == 0) {
//
// //显示已经全部加载完毕
// [self.tableView.mj_footer endRefreshingWithNoMoreData];
// } if (self.page > ) { [self.tableView.mj_footer endRefreshingWithNoMoreData]; } else { [self.dataList addObjectsFromArray:shopList]; [self.tableView reloadData]; //将上拉加载控件弹下去
[self.tableView.mj_footer endRefreshing]; self.page ++ ;
} [ToolHelper showSuccessMessage:@"请求成功"]; } failure:^(NSURLSessionDataTask *task, NSError *error) {
NSLog(@"%@",error); //将上拉加载控件弹下去
[self.tableView.mj_footer endRefreshing]; [ToolHelper showErrorMessage:@"请求失败"];
}];
} //下拉刷新 - (void)loadNewData { NSString * urlString = [NSString stringWithFormat:@"%@%@",SERVER_HOST,API_GetRestaurantsList]; //下拉刷新,上拉加载 请求的地址是一样的 ,只是参数不一样的。
//limit 是不变的、改变 offset。。
// //下拉刷新是加载最新数据,将page页数至为0.
//上拉加载加载更多数据。将page++ //MJRefresh EGO下拉刷新 UIRefreshCotrol 自已写上拉下拉 NSDictionary * params = @{@"full_image_path":@"",
@"geohash":@"wx4u14w0649y",
@"limit":@(shopInfoPageLimit),
@"offset":@(),
@"type":@"geohash",
@"extras[]":@"food_activity",
@"extras[]":@"restaurant_activity"}; [[HttpClient defaultClient] requestWithPath:urlString method:HttpRequestGet paramenters:params prepareExecute:^{ [ToolHelper showProgressMessage:@"我在刷新"]; } success:^(NSURLSessionDataTask *task, id responseObject) {
NSLog(@"%@",responseObject); //JSON -> MODEL 有很多框架,原理都是KVC. //MJExtenstion JsonModel Mantle YYModel //请求的分页数据 +1 self.page = ; //获取最新数据前删除之前的所有数据
[self.dataList removeAllObjects]; NSArray * shopList = [Shop mj_objectArrayWithKeyValuesArray:responseObject]; [self.dataList addObjectsFromArray:shopList]; [self.tableView reloadData]; //重置没有更多的数据(消除没有更多数据的状态)
[self.tableView.mj_footer resetNoMoreData]; //将下拉刷新控件弹上去
[self.tableView.mj_header endRefreshing]; [ToolHelper showSuccessMessage:@"请求成功"]; } failure:^(NSURLSessionDataTask *task, NSError *error) {
NSLog(@"%@",error); //将下拉刷新控件弹上去
[self.tableView.mj_header endRefreshing];
[ToolHelper showErrorMessage:@"请求失败"];
}];
} - (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
} @end

大家是不是觉得少了些什么,当然是cell的自定义了,蛮简单了。看看就好。

ShopIconCell.h ShopIconCell.m

//
// ShopIconCell.h
// CX-小项目(饿了么 网络部分 简单实现)
//
// Created by ma c on 16/3/23.
// Copyright © 2016年 xubaoaichiyu. All rights reserved.
// #import <UIKit/UIKit.h> #import <UIKit/UIKit.h>
#import "Shop.h" @interface ShopInfoCell : UITableViewCell @property (nonatomic, strong) Shop * shop; @end
//
// ShopIconCell.m
// CX-小项目(饿了么 网络部分 简单实现)
//
// Created by ma c on 16/3/23.
// Copyright © 2016年 xubaoaichiyu. All rights reserved.
// #import "ShopIconCell.h"
#import "UIImageView+WebCache.h" static CGFloat kMargin = ; @interface ShopInfoCell () @property (nonatomic, strong) UIImageView * iconView; @property (nonatomic, strong) UILabel * nameLabel; @property (nonatomic, strong) UILabel * descLabel; @end @implementation ShopInfoCell - (void)setShop:(Shop *)shop { _shop = shop; [self.iconView sd_setImageWithURL:[NSURL URLWithString:shop.image_path] placeholderImage:nil]; self.nameLabel.text = shop.name;
self.descLabel.text = shop.desc;
} - (UIImageView *)iconView { if (!_iconView) {
_iconView = [[UIImageView alloc] init];
}
return _iconView;
} - (UILabel *)nameLabel { if (!_nameLabel) {
_nameLabel = [[UILabel alloc] init];
}
return _nameLabel;
} - (UILabel *)descLabel { if (!_descLabel) {
_descLabel = [[UILabel alloc] init];
}
return _descLabel;
} -(instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier { if (self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]) { [self.contentView addSubview:self.iconView];
[self.contentView addSubview:self.nameLabel];
[self.contentView addSubview:self.descLabel]; }
return self;
} - (void)layoutSubviews { [super layoutSubviews]; self.iconView.frame = CGRectMake(kMargin, kMargin, , ); self.nameLabel.frame = CGRectMake(CGRectGetMaxX(self.iconView.frame) + kMargin, CGRectGetMinY(self.iconView.frame), SCREEN_WIDTH - CGRectGetMaxX(self.iconView.frame) - * kMargin, ); self.descLabel.frame = CGRectMake(CGRectGetMinX(self.nameLabel.frame), CGRectGetMaxY(self.nameLabel.frame) + kMargin, CGRectGetWidth(self.nameLabel.frame), ); } - (void)awakeFromNib {
} - (void)setSelected:(BOOL)selected animated:(BOOL)animated {
[super setSelected:selected animated:animated]; } @end

就这样一个小项目就这么的完成了。

IOS-小项目(饿了么 网络部分 简单实现)的更多相关文章

  1. ios学习笔记图片+图片解释(c语言 oc语言 ios控件 ios小项目 ios小功能 swift都有而且笔记完整喔)

    下面是目录其中ios文件夹包括了大部分ios控件的介绍和演示,swift的时完整版,可以学习完swift(这个看的是swift刚出来一周的视频截图,可能有点赶,但是完整),c语言和oc语言的也可以完整 ...

  2. 简单实现一个快速传输电子书到kindle的小项目

    前言 最近翻出来好久没有看的kindle,准备继续我的阅读之路.当然,也是因为发现了一个非常好的获取电子书资源的网站,又燃起了我的阅读兴趣. 然而,往kindle里传输电子书的方式一共有四种: 直接在 ...

  3. 【iOS】小项目框架设计(ReactiveCocoa+MVVM+AFNetworking+FMDB)

    上一个项目使用到了ReactiveCocoa+MVVM+AFNetworking+FMDB框架设计,从最初的尝试,到后来不断思考和学习,现在对这样一个整体设计还是有了一定了理解与心得.在此与大家分享下 ...

  4. web实践小项目<一>:简单日程管理系统(涉及html/css,javascript,python,sql,日期处理)

    暑假自学了些html/css,javascript和python,苦于学完无处练手几乎过目即忘...最后在同学的建议下做了个简单日程管理系统.借第一版完成之际,希望能将实践期间犯过的错误和获得的新知进 ...

  5. C语言实现简单计算器小项目

    昨天刚安装上devc++,半夜想着练练C语言吧 于是就看到实验楼有一个计算器的项目 之前做过一次,这次写的主要是思路 首先我们先从原理思考jia,实现简单的计算器就要具备加减乘除这些,看普通的计算器也 ...

  6. iOS:quartz2D绘图小项目(涂鸦画板)

    介绍:学了quartz2D的绘图知识后,我根据它的一些功能制作了一个小项目:涂鸦画板. 功能:绘制各种图形,还可以选取相册上的照片做涂鸦,然后保存到相册中.其中,还包括功能有:颜色的选取.线宽的选取. ...

  7. python3开发进阶-Django框架学习前的小项目(一个简单的学员管理系统)

    ''' 自己独立写一个学员管理系统 表结构: 班级表: -id -grade_name 学生表: -id -student_name -grade 关联外键班级表 老师表: -id -teacher_ ...

  8. java小项目之:扫雷,这游戏没有你想的那么简单!

    扫雷 我之前分享的小项目和小游戏,电影购票.坦克大战.捕鱼达人.贪吃蛇等,虽然已经是耳熟能详人尽皆知的项目和游戏,但是保不齐真的有人没接触过. 今天分享的这个项目,我不相信没人接触过(仅限80后-00 ...

  9. iOS 开源项目

    在 Github 上 Star 太多了,有时候很难找到自己想要的开源库,所以在此记录下来.便于自己开发使用,也顺便分享给大家. 动画 awesome-ios-animation收集了iOS平台下比较主 ...

随机推荐

  1. Asp.Net 5 新增公告仓库

    一直以来Asp.Net 5 都没有一个比较统一的公告页,对于一个在日夜更新的项目来说,很多人经常会遇到问题但是不知道去哪里寻找帮助,现在Asp.Net 5 项目组新增了一个公告仓库来解决这个问题.  ...

  2. 【腾讯Bugly干货分享】微信终端跨平台组件 mars 系列(二) - 信令传输超时设计

    本文来自于腾讯Bugly公众号(weixinBugly),未经作者同意,请勿转载,原文地址:http://mp.weixin.qq.com/s/9DJxipJaaBC8yC-buHgnTQ 作者简介: ...

  3. 【腾讯优测干货分享】如何降低App的待机内存(三)——探索内存增长的原因

    本文来自于腾讯优测公众号(wxutest),未经作者同意,请勿转载,原文地址:https://mp.weixin.qq.com/s/8BiKIt3frq9Yv9KV5FXlGw 1.3新问题的进一步挖 ...

  4. Flappy Bird 源码走读

    参考:https://github.com/kirualex/SprityBird 该项目基于spritekit,代码的结构很清楚,感觉用来学习spritekit非常不错. 1.项目只有一个viewC ...

  5. .NET基础拾遗(2)面向对象的实现和异常的处理基础

    Index : (1)类型语法.内存管理和垃圾回收基础 (2)面向对象的实现和异常的处理基础 (3)字符串.集合与流 (4)委托.事件.反射与特性 (5)多线程开发基础 (6)ADO.NET与数据库开 ...

  6. Android Secret Code

    我们很多人应该都做过这样的操作,打开拨号键盘输入*#*#4636#*#*等字符就会弹出一个界面显示手机相关的一些信息,这个功能在Android中被称为android secret code,除了这些系 ...

  7. ERP软件的价格设计

    ERP体现出信息流.资金流.物流在供应商.企业.客户间的运营方向,是以销售为源头,生产.物料需求计划为核心,以金额.实时数据为基础的整体.ERP的核心是MRP(物料需求).企业的经营活动最终是为了赢利 ...

  8. 解析大型.NET ERP系统 电子邮件系统帐户集成

    为保证ERP系统的信息流准确快速的传递,需要给系统设计一个消息盒子机制.当系统中发生业务操作后,需要提醒下一个环节的操作人员,以保证ERP信息流快速准确传递.比如生产任务单(工作单,加工单,制单)过帐 ...

  9. AutoMapper对internal访问级别属性的映射

    最近在使用DDD重新搭建公司内部OA的架构,具体情况搭好了应该会写一下,这里说的是今天遇到的问题. 先简单说一下相关的几个部分: 1.聚合.聚合分成了两个模块:一个包含审批单据等估计至少今年不会怎么变 ...

  10. 《JavaScript 源码分析》之 maxlength.js

    /* @author: Terry @params: feedback - the selector for the element that gives the user feedback. Not ...