iOS:使用模板引擎渲染HTML界面


在實際開發中,UIWebView控件接受一個HTML內容,用於相應的界面,下面是該API的接口:

- (void)loadHTMLString:(NSString *)string baseURL:(nullable NSURL *)baseURL

由於HTML內容通常是變化的,所以我們需要在內存中生成該HTML內容。比較簡單粗暴的做法是將該HTML的基本內容定義在一個NSString中,然后用[NSString stringWothFormat]方法將內容進行格式化,示例如下:

//給對應的標簽格式化內容
-(NSString *)demoFormatWithName:(NSString *)name value:(NSString *)value{
    NSString *html =
    @"<!DOCTYPE html>\n"
    "<html lang=\"zh-cn\">\n"
    "<head>""\n"
    "<meta charset=\"utf-8\">\n"
    "<title>這是一個HTML測試</title>\n"
    "</head>\n"
    "<body>\n"
    "<h1>%@</h1>\n"
    "<p>%@</p>\n"
    "<img src=\"http://img3.redocn.com/20131012/Redocn_2013101208320171.jpg\" width=\"256\" height=\"128\"><br><hr>\n"
    "</body>\n"
    "</html>";
    NSString *content = [NSString stringWithFormat:html,name,value];
    return content;
}

但其實我們可以看出,這樣寫並不舒服,因為:

1、模板內容和代碼混在一起,既不方便閱讀,也不方便更改;

2、模板內容的渲染邏輯使用簡單的[NSString stringWothFormat]來完成,功能單一。在實際開發中,我們很可能需要就原始數據進行二次處理,而這些如果模板渲染模塊不能支持,我們就只能自己手工鞋這部分數據二次處理,費時費力。例如,微博的詳情頁面,如果微博的發送時間小於1天,則需要顯示成"xxx小時前",如果小於1分鍾,則需要顯示成"剛剛"。這些界面渲染方便的邏輯如果能夠抽取到專門的排版代碼中,則會清晰很多。

所以我們需要一個模板引擎,專門負責這類渲染的工作。

模板引擎復雜的有:MGTemplateEngine(http://mattgemmell.com/mgtemplateengine-templates-with-cocoa/),它的模板語言比較像Smarty、FreeMarker和Django。另外它可以自由的定義Filter,以便實現上面提到的自定義渲染邏輯。它需要依賴RegexKit,RegexKit是一個正則表達式工具類,提供強大的表達式匹配和替換功能。

也有簡單的是:GRMustache(https://github.com/groue/GRMustache),它比MGTemplateEngine的功能更簡單。另外GRMustache在開源社區更加活躍、更新更加頻繁。

 

對於上面的示例代碼,在使用GRMustache模板后,我們首先需要調整模板的內容:

1、將模板內容放在一個單獨的文件中,方便日后更改,如template.html

2、將原來的%@替換成{{ name }}的形式。

例如調整后的模板內容為:(文件名為:template.html) 

<!DOCTYPE html>
<html lang="zh-cn">
<head>
    <meta charset="utf-8">
    <title>這是一個HTML測試</title>
</head>
<body>
    <h1> {{ name }} </h1>
    <p> {{ content }} </p>
    <img src="http://img3.redocn.com/20131012/Redocn_2013101208320171.jpg" width="256" height="128"><br><hr>
</body>
</html>

即如圖:template.html

然后我們在代碼中將該文件讀取到內存中,再使用GRMustache的renderObject方法生成渲染后的HTML內容,示例代碼如下:

//給template.html中對應的標簽格式化內容
-(NSString *)demoFormatWithName:(NSString *)name value:(NSString *)value{
    NSString *fileName = @"template.html";
    NSString *path = [[[NSBundle mainBundle] bundlePath] stringByAppendingPathComponent:fileName];
    NSString *template = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:nil];
    NSDictionary *renderObject = @{@"name":name,@"content":value};
    NSString *content = [GRMustacheTemplate renderObject:renderObject fromString:template error:nil];
    return content;
}

這樣,我們使用GRMustache模板引擎成功完成了HTML內容的渲染工作,之后就可以通過UIWebView來加載HTML的內容了:

    _webView = [[UIWebView alloc] initWithFrame:self.view.bounds];
    [self.view addSubview:_webView];
    
    //通得模板渲染得到內容(可以隨時修改對應標簽的內容)
    NSString *rendering = [self demoFormatWithName:@"標題" value:@"內容"];
    NSString *path = [[NSBundle mainBundle] bundlePath];
    NSURL *baseUrl = [NSURL fileURLWithPath:path];
    [self.webView loadHTMLString:rendering baseURL:baseUrl];

下載GRMustache框架如下:

  

 Code:

#import "ViewController.h"
#import <GRMustache.h>

@interface ViewController ()
@property (strong,nonatomic)UIWebView *webView;
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    _webView = [[UIWebView alloc] initWithFrame:self.view.bounds];
    [self.view addSubview:_webView];
    
    //通得模板渲染得到內容(可以隨時修改對應標簽的內容)
    NSString *rendering = [self demoFormatWithName:@"標題" value:@"內容"];
    NSLog(@"\n%@",rendering);
    NSString *path = [[NSBundle mainBundle] bundlePath];
    NSURL *baseUrl = [NSURL fileURLWithPath:path];
    [self.webView loadHTMLString:rendering baseURL:baseUrl];
}

//給template.html中對應的標簽格式化內容
-(NSString *)demoFormatWithName:(NSString *)name value:(NSString *)value{
    
    NSString *fileName = @"template.html";
    NSString *path = [[[NSBundle mainBundle] bundlePath] stringByAppendingPathComponent:fileName];
    NSString *template = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:nil];
    NSDictionary *renderObject = @{@"name":name,@"content":value};
    NSString *content = [GRMustacheTemplate renderObject:renderObject fromString:template error:nil];
    return content;
}

@end

打印渲染后HTML內容如下:

2016-12-25 15:21:42.629 JSWeb[1858:83103] 

<!DOCTYPE html>
<html lang="zh-cn">
<head>
    <meta charset="utf-8">
    <title>這是一個HTML測試</title>
</head>
<body>
    <h1> 標題 </h1>
    <p> 內容 </p>
    <img src="http://img3.redocn.com/20131012/Redocn_2013101208320171.jpg" width="256" height="128"><br><hr>
</body>
</html>

webView顯示渲染后的HTML內容如下: 

GRMutstache提供的渲染HTML內容的核心類方法大概有如下這些:

+ (instancetype)templateFromString:(NSString *)templateString error:(NSError **)error;

+ (instancetype)templateFromResource:(NSString *)name bundle:(NSBundle *)bundle error:(NSError **)error;

+ (instancetype)templateFromContentsOfFile:(NSString *)path error:(NSError **)error;

+ (instancetype)templateFromContentsOfURL:(NSURL *)URL error:(NSError **)error;

+ (NSString *)renderObject:(id)object fromString:(NSString *)templateString error:(NSError **)error;

+ (NSString *)renderObject:(id)object fromResource:(NSString *)name bundle:(NSBundle *)bundle error:(NSError **)error;

作者提供的示例如:

// Renders "Hello Arthur!"
NSString *rendering = [GRMustacheTemplate renderObject:@{ @"name": @"Arthur" } fromString:@"Hello {{name}}!" error:NULL];
// Renders the `Profile.mustache` resource of the main bundle
NSString *rendering = [GRMustacheTemplate renderObject:user fromResource:@"Profile" bundle:nil error:NULL];
//Reuse templates in order to avoid parsing the same template several times:
GRMustacheTemplate *template = [GRMustacheTemplate templateFromResource:@"Profile" bundle:nil error:nil];
rendering = [template renderObject:arthur error:NULL];
rendering = [template renderObject:barbara error:NULL];
rendering = ...

更多詳情內容查看github上的源碼:https://github.com/groue/GRMustache

本文參考書籍:《iOS開發進階--唐巧》

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM