以下為個人愚見, 如有不妥,望大家斧正!!!
本文的GitHub源碼下載地址:
https://github.com/DXSmile/JS-OC.git
如需轉載,請注明轉載自DXSmile的
GitHub項目https://github.com/DXSmile/JS-OC.git
簡述:
隨著應用開發(fā)技術的日漸更新迭代, 特別是HTML5出來之后, 現在很多的移動端應用開發(fā)也越來越趨向于使用HTML5的技術來設計和完成相對復雜的UI頁面設計和交互, 就像之前我又一篇文章寫的一樣,
HTML5很可能就是下一個技術的焦點, 很多的語言,平臺,都將會更加兼容HTML5技術,企業(yè)也將會越來越多的使用HTML5, 那么作為一名iOS移動開發(fā)攻城獅來說, 我們就需要不斷的學習成長,盡快弄精通HTML5和OC,和swift的交互,從而來實現更多更新的技術;
前文鏈接如下:
你不得不了解,甚至立馬學習的HTML5
今天我就來和大家簡單的說一下HTML5中,JS代碼和OC代碼的交互, 由于時間關系,我這里只做簡單的描述,具體深入的交互,需要大家后面不斷的練習;
JS和OC的交互方式簡單來說有兩種情況:
交互前提: 在OC端使用webView!!!
1.OC調用JS - OC執(zhí)行JS代碼
步驟1> 顯示頁面,其實就是加載請求 :
使用 [self.webView loadRequest:request];
并且讓控制器成為webView的代理, 監(jiān)聽網頁加載完畢 : 使用<UIWebViewDelegate>的代理方法:
/**
* 網頁加載完畢
*/
- (void)webViewDidFinishLoad:(UIWebView *)webView { }
步驟2> 讓頁面調用OC中的腳本,它屬于webView的一個方法,特別提醒 : 執(zhí)行JS腳本代碼僅僅只有這一種方法:
[webView stringByEvaluatingJavaScriptFromString:@“JS代碼”];
舉例 一:
/**
* 網頁加載完畢
*/
- (void)webViewDidFinishLoad:(UIWebView *)webView
{
NSString *js = @"document.getElementsByTagName('footer')[0].remove();";
[webView stringByEvaluatingJavaScriptFromString:js];
}
舉例 二:
- (void)webViewDidFinishLoad:(UIWebView *)webView
{
NSString *JS代碼 = @"function login (username, pwd) { "
" return 10;"
" }"
" login();";
// 在OC中調用JS的函數(執(zhí)行JS代碼)
[webView stringByEvaluatingJavaScriptFromString:@“JS代碼”];
}
2. JS調用OC - 就是JS調用OC中的方法
步驟1> 需自定義href協議,可以指定方法名和參數 : 然后將OC方法和參數值拼接在一個URL中
如下: 自定義href協議
NSString *onload = @"this.onclick = function() {"
1> 打電話方法,有參數 "window.location.href = 'dx:call:&10086'"
2> 發(fā)信息方法,有參數 "window.location.href = 'dx:sendMsg:&10010'"
3> 關機方法,無參數 "window.location.href = 'dx:shutdown'"
"};";
[imgHtml appendFormat:@"<img onload=\"%@\" width=\"%d\" height=\"%d\" src=\"%@\"><div>",onload,width , height, img.src];
將OC方法和參數值拼接在一個URL中:
/* 通用url的設計
1> 找一個固定的協議: 如 dx:
2> 一般有2個參數 2.1> 方法名 2.2> 方法參數
*/
window.location.href = 'dx:saveImageToAblum:&' + this.src
步驟2> 使用<UIWebViewDelegate>代理協議中的方法攔截請求 : 每次發(fā)送請求之前系統(tǒng)會自動調用該代理方法:
/**
調用 : 每當webView發(fā)送一個請求之前都會先調用這個方法
參數說明:
request : 即將發(fā)送的請求
BOOL : Yes : 允許發(fā)送這個請求 No : 禁止發(fā)送這個請求
navigationType : 是否在新窗口中打開
*/
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
{
// a) 在這個代理方法中攔截JS請求的URL
// b) 從URL中截取相應的方法名和參數
// c) 調用方法虐先,傳遞參數
return YES/NO;
}
小結: 通常情況來說, JS和OC的交互,就是上面兩種情況, 理清思路,就可以很好的做好交互了;接下來就是需要寫代碼了;
下面我附上一份我自己寫的代碼:
#pragma mark - 發(fā)送get請求 獲取數據
/** 發(fā)送get請求,獲取新聞的詳情 */
- (void)getUpData {
// 測試地址: http://c.m.163.com/nc/article/{docid}/full.html
NSString *url = [NSString stringWithFormat:@"http://c.m.163.com/nc/article/%@/full.html", self.headline.docid];
[[DXHTTPManager manager] GET:url parameters:nil success:^(NSURLSessionDataTask * _Nonnull task, NSDictionary *responseObject) {
[responseObject writeToFile:@"/Users/xiongdexi/Desktop/Data/newsDetail.plist" atomically:YES];
// 根據對應的docid賦值
self.detailNews = [DXDetail detailWithDict:responseObject[self.headline.docid]];
// 顯示到webView上
[self showDetailForWebView];
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
NSLog(@"加載出錯, %@", error);
}];
}
接下來需要拼接html代碼:
#pragma mark - 拼接html,顯示數據到webView上
/** 顯示到webView上 */
- (void)showDetailForWebView {
// 1.初始化一個可變字符串
NSMutableString *html = [NSMutableString string];
// 2.拼接html代碼
[html appendString:@"<html>"];
// 2.1 頭部內容
[html appendString:@"<head>"];
// 引入css文件
NSURL *path = [[NSBundle mainBundle]URLForResource:@"DXDetail.css" withExtension:nil];
[html appendFormat:@"<link rel=\"stylesheet\" href=\"%@\">", path];
[html appendString:@"</head>"];
// 2.2 具體內容
[html appendString:@"<body>"];
// 將圖片插入插入body對應的標記中
[html appendString:[self setupBody]];
[html appendString:@"</body>"];
// 2.3 尾部內容
[html appendString:@"</html>"];
// 3. 顯示網頁
[self.webView loadHTMLString:html baseURL:nil];
}
/** 拼接body的內容 (也就是初始化body內容) */
- (NSString *)setupBody {
NSMutableString *bodyM = [NSMutableString string];
// 拼接標題
[bodyM appendFormat:@"<div class=\"title\">%@</div>", self.detailNews.title];
// 拼接時間
[bodyM appendFormat:@"<div class=\"time\">%@</div>",self.detailNews.ptime];
// 拼接圖片 img.ref == <!--IMG#0--> <!--IMG#0--> --> <img src=img.src>
[bodyM appendString:self.detailNews.body];
for (DXDetailImg *img in self.detailNews.img) {
NSMutableString *imgHtml = [NSMutableString string];
// 定義圖片的寬高比 550*344 用下面的方法切割尺寸字符串
NSArray *pixel = [img.pixel componentsSeparatedByString:@"*"];
int width = [[pixel firstObject] intValue];
int height = [[pixel lastObject] intValue];
int maxWidth = [UIScreen mainScreen].bounds.size.width * 0.8;
// 限制寬度
if (width > maxWidth) {
height = height * maxWidth / width; // 數學計算,等比例公式
width = maxWidth;
}
// 拼接圖片
[imgHtml appendString:@"<div class=\"img-parent\">"];
// 給圖片綁定點擊事件onclick
// 注意這里需要先定義一個虛假的協議標記, 讓webView不執(zhí)行跳轉,而是只獲取圖片的url
// 為了預防圖片太大,沒有加載完成就調用了下面的保存方法,可以添加一個限制,用onload來限制讓圖片下載完成之后再執(zhí)行保存
NSString *onload = @"this.onclick = function() {"
"window.location.href = 'dx://?src=' + this.src;"
"};";
[imgHtml appendFormat:@"<img onload=\"%@\" width=\"%d\" height=\"%d\" src=\"%@\">",onload, width, height, img.src];
[imgHtml appendString:@"</div>"];
// 用一個字符串代替另一個字符串 這樣就可以讓標記圖片注釋的部位用一張真正的圖片來替代
[bodyM replaceOccurrencesOfString:img.ref withString:imgHtml options:NSCaseInsensitiveSearch range:NSMakeRange(0, bodyM.length)];
}
return bodyM;
}
CSS代碼: DXDetail.css文件
.title {
text-align : center;
font-size : 25px;
color : black;
font-weight : 5px;
}
.time {
text-align :center;
font-size : 15px;
color :gray;
margin-top : 5px;
margin-bottom : 10px;
}
.img-parent {
text-align :center;
}
JS與OC代碼的交互:
#pragma mark - 用戶點擊圖片后的事件 JS與OC代碼的交互
/** 當用戶點擊圖片時,彈出提示框 并將圖片保存到相冊 */
// 這里需要用到JS代碼和OC代碼的交互
- (void)saveImageToAlbum:(NSString *)imgSrc {
// 1. 提示一個彈窗,提示用戶是否需要保存圖片
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"溫馨提示" message:@"您是否需要將圖片保存到相冊?" preferredStyle:UIAlertControllerStyleActionSheet];
// 1.1 添加兩個按鈕到彈窗上
[alert addAction:[UIAlertAction actionWithTitle:@"是的" style:UIAlertActionStyleDestructive handler:^(UIAlertAction * _Nonnull action) {
// 保存圖片到相冊
[self saveToAlbum:imgSrc];
}]];
[alert addAction:[UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:nil]];
// 1.2 顯示
[self presentViewController:alert animated:YES completion:nil];
}
/** 保存圖片到相冊的代碼封裝 */
- (void)saveToAlbum:(NSString *)imgSrc {
// UIWebView 的緩存由 NSURLCache 來管理
// 獲取緩存對象
NSURLCache *cache = [NSURLCache sharedURLCache];
// 在緩存中取得對應請求的圖片
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:imgSrc]];
NSCachedURLResponse *response = [cache cachedResponseForRequest:request];
NSData *imageData = response.data;
// 保存圖片
UIImage *image = [UIImage imageWithData:imageData];
// 調用保存到相冊的方法 后面三個參數為空,表示保存之后什么都不做
UIImageWriteToSavedPhotosAlbum(image, nil, nil, nil);
}
執(zhí)行<UIWebViewDelegate>的代理方法
#pragma mark - 實現<UIWebViewDelegate>的代理方法
// 調用webView的代理方法之一: 每當webView發(fā)送一個請求之前就會先執(zhí)行一次的方法
// 返回值: YES 表示允許發(fā)送請求, NO表示不允許發(fā)送請求
// 在webView的代理方法中截取圖片路徑,調用保存圖片到相冊的方法
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType {
// 通過url來截圖地址
// 先將發(fā)送的請求里面的url轉換成字符串
NSString *url = request.URL.absoluteString;
// 找到標記所在的方法,確定截取范圍
NSRange range = [url rangeOfString:@"dx://?src="];
// 判斷獲得的range是否不為空,如果不為空,就不允許發(fā)送請求,并截圖范圍之后的字符串,那就是圖片的url
if (range.length > 0) {
// 先確定獲取范圍的長度,
NSUInteger loc = range.location + range.length;
// 根據這個長度,取范圍之后的字符串,就取得圖片的路徑了
NSString *imgSrc = [url substringFromIndex:loc];
// 根據路徑,將其保存到相冊
[self saveImageToAlbum:imgSrc];
return NO;
}
return YES;
}
效果圖:
上面的代碼,只是部分,而且還沒有做代碼的重構,只是實現了功能, 如有需要源碼,可以到我的GitHub首頁下載源碼,
如有不足之處,還望大家斧正!!! 360°感謝!!!