基于 API驅動的 Web APP 的 JavaScript 連接二
接下來的程序代碼如下圖所示:
if ( regUrl.test(this.userInput) && regId.test(this.userInput) ) { this.userInputIsValid = true; var id = regId.exec(this.userInput); this.appId = id[1]; } else { this.userInputIsValid = false; this.appId = ''; }
.test() 方法在正則表達式的語義里表明是去尋找那指定的字串,并且根據制定的校驗規則,確定返回來的是真還是假。 在我們的這個實現方法里面, 我們是通過 regUrl以及 regID兩個參數來進行判斷的,判斷用戶所輸入的鏈接是否以 http://itunes開頭,以及該字串里面是否包含了/id這個字禾人土日。
如果這兩個條件都滿足了,程序就會設置userInputValid為真,并幫助我們把該鏈接里的 ID提取出來,賦值給 appId. 要完成這些,我們就得在輸入之后調用 .exec() 方法。該運行的結果就會返回兩個條目的數組:一個就是完全滿足的正則表達式,另一個就是把/id后面的字串抽取出來的子字串(只所以能完成這個就是因為在括號里面的 (/d+)參數會告訴程序:記住每一個在這里獲得的數字。)所以如果這里調用了.exec()方法,您所應該得到的字串就應該象這樣式的:[“/id12345”, “12345” ]. 而對于我們來說,只要第二種字串即可,所以我們就把第二個參數賦值給 appId 去完成接下來的任務。
如果兩個校驗返回來的為假,那么我們就給userInputIsValid 設置為無效,同時appId也會保持為一個空字串。
現在校驗用戶的輸入是否有效這個功能已經準備好了。所以我們可以繼續我們更多的腳本工作了。
拋出錯誤
現在我們所在的程序節點恰恰就是決定告訴用戶,他所輸入是正確的還是錯誤的,所以我們應該在程序里加上如下的代碼:
if( Gimmie.userInputIsValid ) { /* make API request */ } else { /* throw an error */ }
好了,現在可以開始處理 拋出錯誤 的部分了。應該在程序運行的過程中,有可能因為各種意想不到的情況,讓程序產生錯誤,所以我們應該在程序里面做出一個程序出錯的處理機制,根據出錯的大致類型,給用戶展示相關的錯誤信息。 回憶下,我們到時在 sketch里面所設計的樣式應該是這樣的:
一般出錯信息的展示方式包括這兩部分:錯誤標題就是一個純文本,另外一個就是錯誤的信息體根據出錯的類型展示不同的錯誤信息。所以我們就得寫一段通過出錯信息處理代碼來接受這兩部分。標題主要是描述錯誤,信息體主要是講述錯誤如何產生,以及如何修復。對于指定的例子,比方對于客戶的無效輸入,我們需要特別通知一下客戶,什么才是正確的輸入。所以我們現在就根據傳遞的參數來寫這段錯誤信息代碼吧:
if( Gimmie.userInputIsValid ) { /* make API request */ } else { Gimmie.throwError( 'Invalid Link', 'You must submit a standard iTunes store link with an ID, i.e.
這里,我們主要是調用gimmie.throwError() 函數,并且給該函數傳遞兩個參數:錯誤標題,以及錯誤的信息體。 如果愿意,我們可以直接在這些參數里面就包裝好html的元素。在我們的這個例子里面,在出錯的信息內容里我們把包含的iTunes的鏈接信息用 標簽重點強調給用戶看看,然后提示他們:“嗨,我們所需要的是iTunes 商品的鏈接,您也一定要確定鏈接里面包含了應用的 ID.”
您可以通過 CSS文件來強調 標簽內的強調內容,就比如在這里我們給出錯信息內容加上顏色:
.content--error { color: #196E76; } .content em { font-style: normal; background-color: lightyellow; }
現在,您就可以在Gimmie對象寫 throwError 函數的代碼了:
var Gimmie = { /* prior code here */ throwError: function(header, text){ this.$content .html('' + header + ' ' + text + '
') .addClass('content--error'); this.toggleLoading(); } }
注意到我們已經獲得了 this.$content. 這里也可以寫成 $(‘.content’) 來獲取選擇的值。但我們要把所選擇的內容做為一個變量存到了 Gimmie對象中了,是因為在這段程序里,我們要不斷的用到他。所以我們在這里的引用使用的是 this.$content. 現在就可以把 HTML頁面內容設置為 $content 傳遞過來的內容了,我們已經在頁頭的樣式表里把文字樣式設置成為加粗顯示了,所以這里要新加一個字體樣式以顯示我們想給出錯信息設置的字體形式,這個字體形式類為:content-error. 最后,再次調用 toggleLoading()函數清除掉加載類,并且不再顯示加載圖標了。
到現階段,如果您在程序里輸入一個錯誤的 URL, 比方: http://www.xn--vhqr8ojt1avja.com, 或者您輸入的鏈接是用 iTunes URI 開頭的,但是并不包含應用的 ID,比方: http://itunes.apple.com/us/app/優聯實達. 這時用戶就可以看到如下的出錯信息了。
![]()
讓我們再來擴展一點出錯的功能,在那些支持的瀏覽器中,我們可以在程序拋錯時加一個小的 彈出動畫。 要實現這個,我們就得加載/稱掉這段為文字準備的小動畫樣式表。把如下的代碼加進CSS文件吧:
.content--error-pop { -webkit-animation: pop .333s; -moz-animation: pop .333s; -o-animation: pop .333s; animation: pop .333s; } @-webkit-keyframes pop { 0% {-webkit-transform: scale(1);} 50% {-webkit-transform: scale(1.075);} 100% {-webkit-transform: scale(1);} } @-moz-keyframes pop { 0% {-webkit-transform: scale(1);} 50% {-webkit-transform: scale(1.075);} 100% {-webkit-transform: scale(1);} } @-o-keyframes pop { 0% {-webkit-transform: scale(1);} 50% {-webkit-transform: scale(1.075);} 100% {-webkit-transform: scale(1);} } @keyframes pop { 0% {-webkit-transform: scale(1);} 50% {-webkit-transform: scale(1.075);} 100% {-webkit-transform: scale(1);} }
這就可以讓您的出錯信息放大或縮小,有一個好象被彈出來的效果了。我們再用 Javascript 來控制下何時加載這段樣式表,何時移除。 所以在 throwError 函數中要加上如下的代碼:
throwError: function(header, text){ // Remove animation class this.$content.removeClass('content--error-pop'); // Trigger reflow // https://css-tricks.com/restart-css-animation/ this.$content[0].offsetWidth = this.$content[0].offsetWidth; // Add classes and content this.$content .html('' + header + ' ' + text + '
') .addClass('content--error content--error-pop'); this.toggleLoading(); },
把這些新加的代碼布署好到您的應用服務器上面,測試一下如果您現在輸入錯誤的信息,錯誤提示的顯示是否和您預期的一樣:
![]()
提交 API 請求
我們離成功越來越近了。現在我們可以檢查,用戶提交的鏈接是否正確,我們也提供了錯誤信息,提示用戶的錯誤操作, 所以現在就可以正式提交 API請求了。
這段提交請求,可以直接放在 if() 的判斷語句里:
if( Gimmie.userInputIsValid ) { $.ajax({ url: "https://itunes.apple.com/lookup?id=" + Gimmie.appId, dataType: 'JSONP' }) .done(function(response) { // when finished }) .fail(function(data) { // when request fails }); } else { /* our other code here */ }
代碼里可以看出來,我們在這里提交的是一個 AJAX 請求給 iTunes API. 還記得我們在前面提到過,iTunes API 有一個 lookup 的鏈接,我們可以通過點擊該鏈接拿到想要的信息。 該返回信息是用如下的格式:http://itunes.apple.com/lookup?id=***. 后面這串數字就是您想要得到的應用的 ID。 API 給了我們一個 Yelp 應用的例子: https://itunes.apple.com/lookup?id=284910350. 把這個鏈接輸入您的瀏覽器,會得到一段 JSON代碼如下所示:
![]()
稍稍處理一下這段代碼的格式,象 JSON代碼一樣排排版,您就會得到更容易看懂的代碼如下圖所示:
![]()
查看 API 的幫助文檔,您會注意到該 API可以提供在iTunes商品里的各種內容的返回值:從音樂到電影到應用程序。 這對我們很有用,表明我們的這個小程序就不僅僅可以獲得移動應用的圖標了,同時也可以得到所有MAC系統的應用圖標!Mac 系統的圖標所用到的鏈接地址和 iOS 的應用類型是一樣的。 例如: FCP 的鏈接如下所示: https://itunes.apple.com/us/app/final-cut-pro/id424389933?mt=12. 我們很熟悉的格式了,以 http://itunes 開頭, 同時里面包含該應用的 ID信息了,這些都是我們需要的。
在出錯處理函數中的判斷語句里面,再加上一些相關的內容,用來處理提交API請求出錯的問題吧:
if( Gimmie.userInputIsValid ) { $.ajax({ url: "https://itunes.apple.com/lookup?id=" + Gimmie.appId, dataType: 'JSONP' }) .done(function(response) { // when finished }) .fail(function(data) { Gimmie.throwError( 'iTunes API Error', 'There was an error retrieving the info. Check the iTunes URL or try again later.' ); }); } else { /* our other code here */ }
由于我們已經把出錯的問題都專門提取出來做為一個專門的函數了,所以再處理其它的出錯問題就相當容易了。
響應
現在讓我們開始處理當請求成功完成后,程序應該做些啥?
$.ajax({ /* other code here */ }) .done(function(response) { // Get the first response and log it var response = response.results[0]; console.log(response); }) .fail(function(data) { /* other code here */ });
注意這里,我們得到了API 的響應,并且把第一個結果記錄到控制臺上。 如果您查看 API 請求的例子,就可以看到在 JSON 對象的最上面有一個參數 resultCount, 該參數表明了該對象的返回結果數量(對于我們的 lookup 方法來說,返回結果應該只有一個),同時也指明了具體是哪一個結果數組儲存了我們想的返回數據(在我們的例子中,該結果也是只有一個)
![]()
根據這個我們就把該響應賦值給結果的第一個項目同時記錄到控制臺里。 如果您打開了我們的小應用并且輸入了鏈接地址,比方:https://itunes.apple.com/lookup?id=284910350 您會注意到我們的程序被卡在加載狀態了。此時通過查看開發者工具,并用打開控制臺,您會看到 API 的響應其實是已經被記錄,我們現在可以使用 JavaScript 來使用這些資源了。
![]()
如同您所見: API返回了一大堆 APP 的詳細信息: 名字,開發者,描述,類別,價格,以及其它。 我們其實真正需要的很少,就是該應用的圖標。 所以我們就來查看一下這些返回的信息里是否有我們需要的。
$.ajax({ /* other code here */ }) .done(function(response) { // Get the first response and log it var response = response.results[0]; console.log(response); // Check to see if request is valid & contains the info we want // If it does, render it. Otherwise throw an error if(response && response.artworkUrl512 != null){ Gimmie.render(response); } else { Gimmie.throwError( 'Invalid Response', 'The request you made appears to not have an associated icon. Try a different URL.' ); } }) .fail(function(data) { /* other code here */ });
仔細查看后發現:response.artworkUrl512 正是我們所需要的信息。 artworkUrl512 正是 API返回的全尺寸應用圖標的關鍵字。既然已經得到了我們需要的信息,下一步就是把他們在頁面上展示出來。 為了實現,我們需要開發另外一個函數名字叫做 render. 如果出現了一些其它異常的情況,就用我們已經開發好的出錯處理機制拋出錯誤即可。
展示 API返回結果
我們已經拿到 API返回的結果了,就讓我們把他們顯示到頁面上吧。 一旦我們判斷出來所需要的信息都已經拿到手后,就讓程序調用 Gimmie.render(response) 函數,同時把API的 response 參數傳遞過去,該參數可是包含了重要的應用程序關鍵字。 所以返回到 Gimmie 對象, 開始創建 render 函數吧。
var Gimmie = { /* our other code here */ render: function(response){ var icon = new Image(); icon.src = response.artworkUrl512; icon.onload = function() { Gimmie.$content .html(this) .append('' + response.trackName + '
') .removeClass('content--error'); Gimmie.toggleLoading(); } } }
這段代碼中,我們主要做如下工作:
- 從頭開始構造一個圖像類,我們創造一個變量名字為 icon, 同時調用了用來創建 HTMLImageElement 的 Image()構造器。考慮他就象使用 JavaScript 腳本文件在內存中創建
.
- 利用 Image()構造器的icon.scr 方法給我們的圖像設置src 屬性,然后把我們從 API 響應中拿到的圖片地址信息: artworkUrl512 賦值給 src屬性。這就可以告訴瀏覽器到指定的位置去拿該圖標。
- 我們使用 icon.onload 方法告訴瀏覽器,當完成了圖像抓取工作后,應該做這個了。。這種方法可以保證瀏覽器在完成了所有圖片抓取工作以后,才把圖象文件真正的放進文檔對象模型中。
- 在 icon.onload 里面我們給 HTML的標簽 $contents 設置為剛剛得到的圖片文件。 同時也可以添加更多的您想在這個區域展示的信息。 在這個例子中,我從 API的響應中獲得了 trackName,所以就會在這個地方和圖標一起把應用的名字也展示出來。
- 最后執行 toggleLoading 函數,因為我們已經加載了所有的東西。
打開應用,輸入示例的鏈接地址:https://itunes.apple.com/us/app/yelp/id284910350?mt=8 您就會得到一個很漂亮的圖標文件在瀏覽器里。
![]()
再試一個Mac 系統的應用,比方Final Cut Pro吧: https://itunes.apple.com/us/app/final-cut-pro/id424389933?mt=12
![]()
加載圖標蒙板
現在應用里面加載的圖標并不是圓角的。 我們在前面早已經提過了,大部分的iOS圖標并不是在設計的時候就做成了圓角。 這個效果是在應用的操作系統級別實現的。對于 iOS的圖標來說,我們得把之前在 sketch中創建的蒙板效果加上去。 所以您先回到sketch項目中,把當時設計的蒙版文件輸出來,放進我們的系統中,以備系統在加載圖標的時候,可以在上面加上該蒙版。
var Gimmie = { render: function(response){ var icon = new Image(); icon.src = response.artworkUrl512; icon.onload = function() { Gimmie.$content .html(this) .append('' + response.trackName + ' Actual icon dimensions: ' + this.naturalWidth + '×' + this.naturalHeight + '
') .removeClass('content--error'); Gimmie.toggleLoading(); // If it's an iOS icon, load the mask too if(response.kind != 'mac-software') { var mask = new Image(); mask.src = 'assets/img/icon-mask.png'; mask.onload = function() { Gimmie.$content.prepend(this); } } } } }
我們做了如下的工作:
- 在API的結果集里,有一個叫做 kind 的對象,該對象標明的從API返回的結果的類型,比方是電影,音樂還是軟件。 Mac 應用的 kind值應該是: mac-software. 因為 Mac 應用不需要圓角蒙版,所以我們得檢查一下,如果響應里的類型屬性為非 mac-software的,才需要加載蒙版。
- 這里也要調用同一個 Image()構造器,我們在前面加載圖標的時候已經用過了。在這里我們把src設置為蒙版的圖片,提前把這個圖片加載到系統中,等加載程序加好了我們所要圖標的時候一起使用。
現在我們再把下面的代碼加到 CSS文件里面為該蒙版指定樣式。
.content img[src*="icon-mask.png"] { position: absolute; left: 0; top: 0; }
終于完成了。再試一次輸入Yelp 鏈接地址,這次就會出現如你所想的帶圓角的應用程序圖標了。
![]()
完成
這一過程還挺長,我是真心希望您在這里學到了些東西。我們在不同的階段創造了不同東西,包括設計的線框圖到不同的模型。 我們也談到用HTML, CSS 以及 Javascript 一起來開發 web App, 以實現該應用和第三方API的交互。
希望您已經領會了API交互的精髓。 您已經學會了如何動態從第三方的 API拿到相應的資料,并把他展示在網頁上。 基于這個基礎,您可以真正的開始針對您所感興趣的應用程序大展拳腳了。
下面我列出一些有可能對您有幫助的第三方就算程序的API:
本系列完!
不深思則不能造于道。不深思而得者,其得易失。
名人名言- 曾國藩
- By 優聯實達(譯)
- 2015-10-14
- 2686
- 公司新聞,網站開發,網站設計,UI