溫暖.jpg
前言
最近的幾個項目中都需要加載大量的HTML,需要將HTML中的圖片在點擊時實現原生預覽。由于HTML的來源很復雜,包括有后臺框架編輯的、第三方提供的、網絡抓取的等等。所以只能采取獲取HTML之后前端注入JS事件來觸發圖片點擊事件,獲取當前頁面的所有圖片地址。由于實現的原理很簡單(兩行代碼),就不需要使用JavaScriptCore或者其他第三方框架了。
實現效果
HTMLImage.gif
框架整體介紹
- 該框架為一個通用HTML圖片預覽框架,旨在提供一種簡單快捷的調用方式來native預覽網頁圖片。
- 同時支持UIWebView與WKWebView。
- 支持網頁圖片自定義過濾規則。過濾“頭像、廣告”之類的小圖標。
- 支持用戶自定義核心抓取圖片JS、自定義解析規則。
- 支持配置參數確定是否僅抓取正文(conent)部分圖片。
- SDK支持解析懶加載類型HTML網頁(ps:簡書更新以后圖片加載就是采用的滾動加載模式)
實現原理
- HTML加載完成之后注入圖片點擊的JS。
- 截取JS的點擊事件并拆分出所有圖片URL和當前點擊圖片URL。
- 通過OPTION配置項、配置相關業務參數。
- 自動解析懶加載類型HTML網頁、允許用戶自定義懶加載核心屬性。
注入圖片點擊JS需要完成的功能
- 點擊圖片能夠響應圖片的點擊事件。
- 能夠獲取當前點擊圖片的URL。
- 能夠獲取當前HTML中的所有圖片URL。
- 能夠將圖片點擊事件與網頁自帶點擊事件區分開來。
- 能夠將當前點擊圖片URL與所有圖片URL區分開來。
截取JS的點擊事件解析URL
- 根據標識符判斷點擊是否執行圖片預覽功能
- 根據分隔符拆分當前點擊圖片URL與所有圖片URL。
- 根據分隔符將所有圖片URL合并成圖片數組。
- 具體業務過濾不合法圖片URL(eg:包含logo等)。
核心JS代碼實現
// 通知 iPhone UIWebView 加載 url 對應的資源
//PhoneGap處理方式
function loadURL(url) {
var iFrame;
iFrame = document.createElement("iframe");
iFrame.setAttribute("src", url);
iFrame.setAttribute("style", "display:none;");
iFrame.setAttribute("height", "0px");
iFrame.setAttribute("width", "0px");
iFrame.setAttribute("frameborder", "0");
document.body.appendChild(iFrame);
// 發起請求后這個 iFrame 就沒用了,所以把它從 dom 上移除掉
iFrame.parentNode.removeChild(iFrame);
iFrame = null;
}
function zwPreviewImageClickAction(){
var imgs=document.getElementsByTagName('img');
var length=imgs.length;
var allSrc='';
for(var i=0;i<length;i++){
var img=imgs[i];
var imaSrc = '';
if (img.src.length){
imaSrc = img.src;
}else{
imaSrc = img.getAttribute('data-original-src');
}
if (allSrc.length) {
allSrc = allSrc+'^^^'+imaSrc;
}else{
allSrc = imaSrc;
}
}
for(var i=0;i<length;i++){
var img=imgs[i];
img.onclick=function(){
// window.location.href='zw-image-preview:'+allSrc + '###'+this.src;
loadURL("zw-image-preview:"+allSrc+ '###'+this.src);
}
}
}
zwPreviewImageClickAction();
截取JS事件并解析URL
- UIWebView在shouldStartLoadWithRequest代理方法中
- WKWebView在decidePolicyForNavigationAction代理方法中
if ([request.URL.scheme isEqualToString:@"zw-image-preview"]) {
NSString *urlPath = [request.URL.absoluteString substringFromIndex:[@"zw-image-preview:" length]];
NSArray *mixURLArray = [urlPath componentsSeparatedByString:@"###"];
//圖片地址合集
NSString *allImageURL = [mixURLArray firstObject];
//當前實際點擊圖片的地址
NSString *indexImageURL = [mixURLArray lastObject];
}
實際項目中遇到的問題
- HTML來源與展示界面比較復雜,無法統一WebView界面。導致以上代碼需要重復調用多次。
- HTML的格式比較奇葩,鬼知道后臺使用的什么轉換器。
- 圖片地址命名會出現與分隔符沖突等等。
- HTML中混雜了小圖標(logo、頭像等)需要過濾。
封裝JS與URL解析
為了避免重復調用,快速實現功能。對上述功能做了簡單的封裝。
- UIWebView實現以下兩行代碼即可
-(void)webViewDidFinishLoad:(UIWebView *)webView{
self.htmlSDK = [ZWHTMLSDK zw_loadBridgeJSWebview:webView];
}
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType {
if ([self.htmlSDK zw_handlePreviewImageRequest:request]) {
return NO;
}
return YES;
}
- WKWebView實現以下兩行代碼
-(void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation{
self.htmlSDK = [ZWHTMLSDK zw_loadBridgeJSWebview:webView];
}
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler {
decisionHandler(WKNavigationActionPolicyAllow);
[self.htmlSDK zw_handlePreviewImageRequest:navigationAction.request];
}
效果展示
normalPreview.gif
SDK源碼解析
- 加載HTML中的所有圖片,包括推廣廣告圖、logo、用戶評論頭像等等。參照上圖:包括了簡書的logo、下文的推廣鏈接圖。
self.htmlSDK = [ZWHTMLSDK zw_loadBridgeJSWebview:webView];
- 僅加載標準正文content中的所有圖片(例如簡書中正文文章中所有圖片),增加了過濾條件OPTION_StandardCoreJS。
self.htmlSDK = [ZWHTMLSDK zw_loadStandardBridgeJSWebview:webView];
- 如果以上還是不能滿足需求,需要過濾更多的HTML圖片信息,則需要自定義option過濾器。eg:僅加載正文HTML圖片、過濾掉所有圖片URL包含有logo、avaters的圖片。
ZWHTMLOption *option = [[ZWHTMLOption alloc] init];
option.getAllImageCoreJS = OPTION_StandardCoreJS;
option.filterURL = @[@"logo",@"avaters"];
self.htmlSDK = [ZWHTMLSDK zw_loadBridgeJSWebview:webView withOption:option];
- 需要加載執行自定義的JS
ZWHTMLOption *option = [[ZWHTMLOption alloc] init];
option.zwPreviewJS = @"自定義的JS";
self.htmlSDK = [ZWHTMLSDK zw_loadBridgeJSWebview:webView withOption:option];
圖片預覽顯示
- 按照上面兩行代碼實現調用即可預覽顯示。SDK內部已經封裝了圖示的顯示模式。
//預覽視圖、已集成SDK中
ZWPreviewImageView *showView = [ZWPreviewImageView showImageWithArray:allImageArray withShowIndex:index];
[showView showRootWindow];
- 如果用戶需要自定義(嫌棄>_<)圖片瀏覽器,只需要實現調用以下的block。allImageArray:過濾后所有URL數組。index:當前操作圖片的序號。
self.htmlSDK.blockHandlePreview = ^(NSArray *allImageArray, NSInteger index) {
//自定義圖片預覽
};
如何使用SDK
強烈建議您使用pod導入,節省導入依賴的時間。
- 使用cocoaPods導入(搜索不到請更新本地倉庫)
pod 'ZWHTMLImage', '~> 0.0.2'
- 直接將文件ZWHTMLImage拖入工程中
依賴ZWPhotoPreview圖片顯示框架。
#import "ZWHTMLSDK.h"
關于圖片保存權限
- 長按保存功能需要用戶info.plist中配置權限
Privacy - Photo Library Additions Usage Description
源碼
源碼放在GitHub上,歡迎指正,記得star哦!
v0.0.2版本更新記錄
【新增】: 支持懶加載類型網頁圖片的讀取功能。
【修改】: 重新構造圖片預覽功能、更新圖片預覽框架ZWPhotoPreview最新版本。
【新增】: 提供圖片快速預覽、手勢拖放動畫、手勢縮放、長按保存、頁碼選擇等最新功能。
v0.0.1版本更新記錄
- 【新增】: 提供簡便的HTML圖片放大預覽功能。
- 【新增】: 提供簡便的HTML圖片過濾功能、用戶自定義過濾參數。
- 【新增】: cocoapods支持。