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

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

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

这一采用的是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. API Monitor简介(API监控工具)

    API Monitor是一个免费软件,可以让你监视和控制应用程序和服务,取得了API调用. 它是一个强大的工具,看到的应用程序和服务是如何工作的,或跟踪,你在自己的应用程序的问题. 64位支持 API ...

  2. ASP.NET Web API 开篇示例介绍

    ASP.NET Web API 开篇示例介绍 ASP.NET Web API 对于我这个初学者来说ASP.NET Web API这个框架很陌生又熟悉着. 陌生的是ASP.NET Web API是一个全 ...

  3. ASP.NET MVC 描述类型(二)

    ASP.NET MVC 描述类型(二) 前言 上个篇幅中说到ControllerDescriptor类型的由来过程,对于ControllerDescriptor类型来言ActionDescriptor ...

  4. Thread.Sleep(0) vs Sleep(1) vs Yeild

    本文将要提到的线程及其相关内容,均是指 Windows 操作系统中的线程,不涉及其它操作系统. 文章索引 核心概念 Thread.Yeild       Thread.Sleep(0) Thread. ...

  5. javascript中的Function和Object

    写的很好,理解了很多,特此转发记录 转自:http://blog.csdn.net/tom_221x/archive/2010/02/22/5316675.aspx 在JavaScript中所有的对象 ...

  6. 被逼着写的jquery工作日管理日历插件

    因为工作原因,在我刚进入新公司之后,立马要求让我做一个jquery的插件demo.我的天,我面试的可是.net工程师啊.虽然以前接触过js,jquery,但也只是接触过一丢丢啊,没办法,只好硬着头皮上 ...

  7. 阿里云自定义日记文件无法通过ftp下载

    异常处理汇总 ~ 修正果带着你的Net飞奔吧!http://www.cnblogs.com/dunitian/p/4599258.html 有可能是个例,xftp不行(对linux支持很好),Cute ...

  8. 持续集成:CruiseControl.NET + VisualSVN.Server

    刚换了工作,有需要搭建一套持续集成的平台,做一下总结. 首先是我用到的工具: 上面缺少了Microsoft Fxcop,可以用来做代码校验,不过实际情况暂时还没有用到.主要的需求目前是,使用已发布的稳 ...

  9. linux mount/umount挂载命令解析。

    如果想在运行的Linux下访问其它文件系统中的资源的话,就要用mount命令来实现. 2.      mount的基本用法是?格式:mount [-参数] [设备名称] [挂载点] 其中常用的参数有: ...

  10. 跨域之jsonp

    我们都知道使用<script>标签可以引入外部的JS文件,即使这个JS文件来自于其他的网站,比如我们引用存放在网络服务器上的jQuery框架.在这个过程中,我们已经实现跨域访问.像< ...