2012年5月31日 星期四

JavaScript 更新 DOM elements 好卡

最近被問到一個 JavaScript 的問題,我覺得算是滿基本的。所以我很直覺的用一般的思維回答了錯誤的答案。 後來被糾正之後,我才恍然大悟最近再看的一些 UI 卡卡的問題的根本原因。

這個問題大概是這樣:
上面這段 Code 執行之後,Ajax 的 onSuccess handler 會不會在 for loop 到一半的時候被呼叫?還是會等到整個 postData 離開之後才有機會被呼叫呢?

我想大概只有我才會傻傻的說要看 for loop 有多 heavy ... 我完全忘了考慮瀏覽器上的 JavaScript 環境都是 single thread,每一個 segment 都是一個 event request,而瀏覽器的 event queue 一次只有一個 event 能被處理。換句話說,當 postData 這個 function body segment 被執行的時候,是沒有任何人插的進去的。就算網路超快,Ajax request 立刻回來也沒機會立刻執行 onSuccess,一定要等到 postData segement 離開為止才有機會繼續處理 event queue 中的下一個 event!

我剎那間一驚,就是這個卡住我 UI 啊。 
這樣寫的話 for loop segment 整個是一個 event ,每個 append 的 function call 都被 append 到 event queue 後面,所以想像一下如果 for loop 裡面做太多事情 update dom elements,你就會覺得整個 UI 卡住。但如果是寫 Web Application 很像不知不覺就會這樣寫。解決方法其實很容易,只要想辦法讓 for loop 的每一個 run 都變成一個獨立 event 就可以了。

最直覺得方式是這樣改:

但是這有個很嚴重的問題是如果 loop 裡有用到 i 的話會意想不到的 i 永遠都是 1000!

所以比較好的應該是:
setTimeout 是一個很好的 trick 來建立獨立的 event 丟到 event queue 裡面,而時間值給 0 代表的是儘快的執行。這樣一改寫之後 browser 就會有機會可以在中途處理 user input event 並且也能夠看起來即時地更新 UI。

那些年,我寫 Android 所犯的錯(一):君要臣死,臣 FB

我本來以為, Android 裡的 Activity 就像以前寫的程式一樣,除非自我走到盡頭(正常結束),又或是自爆(嚴重問題當機),大部份都是君(使用者)要臣(程式)死,臣非死不可(FB)。但是在 Android 裡, Android 通常會在資源不夠的情況下,而且皇帝沒有召見你(Invisible)的時候,叫你先自盡(Destroy),等到皇帝召見,再從黃泉召喚你回來(Create)。

開始用正常的口吻來描述問題。大部份的人都會看 Android 文件來了解 Activity 的生命週期。裡面有說到:
” If an activity is paused or stopped, the system can drop the activity from memory by either asking it to finish, or simply killing its process. When it is displayed again to the user, it must be completely restarted and restored to its previous state.”
中譯:”如果 Activity 是在暫停或是已停止的狀態下,系統可以將 Activity 從記憶體中剔除。當這個 Activity 要再被秀出來時, Activity 本身一定要能完整的重新開始,並且回到原本的狀態。”

我天真的以為,一切大不了重頭開始,又是一條好漢,但杯具就這樣端出來了。所以,這裡一定要強調一下 onSaveInstanceState 這個函式。 onSaveInstanceState 就是如何讓 Activity 可以回到原先狀態的重要角色。 先來簡單描述一下悲劇。以下是一段叫 Android 的照相程式起來拍張照片傳給自己的程式碼。
public class GetPhoto extends Activity {
 private Uri mImageUri;
 protected void onCreate(Bundle savedInstanceState){
  super.onCreate(savedInstanceState);
  setContentView(R.layout.main);
 }
 //叫系統拍照程式起來的函式
    private void enterCameraMode(){
  File exFolder = Environment.getExternalStorageDirectory();
     File file = new File(exFolder, "temp.jpg");
  //準備好要叫拍照程式存的URI
     mImageUri = Uri.fromFile(file);
     Intent i = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
  //將URI傳給拍照程式
     i.putExtra(MediaStore.EXTRA_OUTPUT, m_imageUri);
     startActivityForResult(i,0);
    }
 //拍照程式結束後,由此函式將結果帶回
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data){
     super.onActivityResult(requestCode, resultCode, data);
     if (resultCode == RESULT_OK){
      // 使用mImageUri來操作拍照完的檔案
     }
    }
}

看似一切和平,但問題就出在,當照相程式起來之後,系統叫你自盡。然後拍完照的時候,再叫你重新做人,並且在 onCreate 完後呼叫 onActivityResult 。這時候,如果你沒有好好回復當初的 URI ,輕則抓不到照片,重則使用空的URI就當場自爆,很不幸的,那些年,我是走向自爆那一個人。後來我就乖乖的補上以下的程式。
protected void onCreate(Bundle savedInstanceState){
 // 省略…
 if (savedInstanceState != null){
  String filename = savedInstanceState.getString(”SAVED_URI_PATH”, "");
  if (filename.length() > 0){
   File savedFile = new File(filename);
   mImageUri = Uri.fromFile(savedFile);
  }
 }
 // 省略…
}
@Override
protected void onSaveInstanceState(Bundle outState){
    super.onSaveInstanceState(outState);
    if (mImageUri != null){
     String filename = mImageUri.getPath();
        outState.putString(”SAVED_URI_PATH”, filename);
    }
}

所以,養成好習慣,在寫 Activity 時,仔細的思考要不要乖乖加個 onSaveInstanceState ,並在 onCreate 時回復該有的設定,皇上不希望下次召見你時,從一個達官貴人,變成一條赤裸裸的好漢。

2012年5月22日 星期二

怎樣的短篇文才吸引人


來篇跟Coding沒關係,但也是大家在敲鍵盤所做的事。(硬要扯關係)
摘錄自【哈佛商業評論】20125月號的內容【打造網路微言的大義】。
這是探討推特Twitter的研究結果,能不能用在臉書facebook的粉絲團,就有靠大家的經驗分享了。
首先,參與此項評等研究的人以科技圈為主,而且愛看新聞,請特別注意。
研究結果顯示,最好的推文依序如下(第五項之後請盡量避免):
1.    隨筆 Random Thought
當然,要是有趣和刺激的推文,如果沒有符合資格,還是別發吧。
2.    自我促銷 Self-Promotion
推文提供連結,導向自己的作品,是有實用價值的。(因為是科技圈的才有這種效果?)
3.    對關注者提問 Questions to Followers
透過提問的形式來集思廣益,是推特的核心功能之一。
4.    資訊分享 Information Sharing
許多關注者使用推持取得新資訊。因此,提供情境式連結,避免轉貼舊新聞,還要力求簡潔扼要。
5.    意見或抱怨 Opinion or Complaint
除非你的推文特別機智詼諧或實用。
6.    我正在做什麼 Me Now
如果沒有人問你正在做什麼,推文卻硬要提起,別期望會有很多人喜歡。
7.    談話 Conversation
關注者很不喜歡這種做法,因為感覺就像在聽別人的私密談話。
8.    保持露臉 Presence Maintenance
這種推文被認為一點用處也沒有,而且無聊至極。

研究總結,如果希望關注者持續對你的推文感興趣,語義務必清楚,不要曖昧不明,不要過度使用主題標籤 - # (hashtag),不要專發佈一對一的對話。
共同研究人員Paul Andrè說:【關鍵在於把關注者放在心上,以及了解每個人的價值觀可能不一樣。】

2012年5月20日 星期日

SEO 幼幼班 (二) - 在你開始做 SEO 之前要檢查的三件事情

Kindergarten

這是之前寫過的 SEO 幼幼班的系列延伸,這部份的文章都是記錄我從各方面知道的心得。當然跟真正的 SEO 專家比這些一定是太淺,不過我相信如果是跟我一樣的門外漢,相信應該可以有些收穫。

前幾天有人看完 SEO 幼幼班(一)之後,問我說:「接下來是不是就要開始講網站架構怎麼弄?關鍵字怎麼挑?」當然,我們常常可以看到講 SEO 的文章都專注在這方面的內容,但是既然是幼幼班,當然要來寫點更基礎的,今天就來講講在你開始做 SEO 之前要檢查的三件事情。

sitemap 登錄了嗎?

SEO 最重要的是什麼?就是讓 Search Engine 可以找到你。雖然 Search Engine 的 robot 會自動對你的網站依照連結做抓取,但是透過 sitemap,可以讓搜尋引擎更容易知道要爬取哪些網頁、哪些網頁是重要的、以及網頁的更新日期等等的資訊。關於 sitemap 的格式可以參考這邊,在 sitemap 建好之後,別忘了去 Google WebmastersBing Webmaster 等地方登錄網站的 sitemap。

robots.txt 內容是對的嗎?

robots.txt 是告訴 Search Engine Robot 可以怎麼樣抓取你網站的檔案,關於 robots.txt 要怎麼寫,可以參考這裡

之前我曾經幫我某朋友看過一個網站,他想知道為什麼他的網站架了一陣子之後還是沒有被搜尋網站收錄到。找了半天才發現他外包的網頁公司竟然把實際上線 robots.txt 的內容寫成:

User-agent: *
Disallow: /

當然這種愚蠢例子應該是比較不容易時常發生,不過把 robots.txt 的內容寫好,可以更直接的讓 Search Engine 搜尋到你讓他搜尋的網頁,並且避免他找到你不希望別人看到的網頁。

Google Analytics 裝了嗎?

Google Analytics 可以說是對於做網站的人來說最重要的工具之一。我們做 SEO 的目的是什麼呢?是希望使用者可以從搜尋引擎搜索到我們的網站,並且得到他們需要的資料。因此我們需要知道使用者是搜索哪些關鍵字進來的?這些關鍵字曝光效益怎樣?他們是不是可以找到他們想要的頁面?Google Analytics 能做的事情太多了,怎麼分析這些數字這部份往後會找時間慢慢說,但是無論如何請先把 Google Analytics 裝起來,並且和 Google webmasters 當中的設定整併在一起。這樣子日後才可以對這些數據進行更深的分析。

檢查看看你的網站這些都做好了嗎?如果還沒有做好那記得趕快把缺的補上,這樣會對日後的做 SEO 才會有更加相輔相成的功效。

Reference:

2012年5月17日 星期四

環狀使用者介面之我見



這篇文章純粹是要講我個人對 Circle UI 的偏好。所以如果你不欣賞 Path UI 的話記得別看下去噢 XDD 


大約將近一年前我有幸在某家公司參與全新版本功能的討論,又很幸運的我剛好是可以提供一些新 idea 出來被打槍的人,所以我就理所當然地提出了我『愛』的 Circle UI,我還寫 Code 去 demo 了。那天 demo 前我很興奮,我自己覺得這個 UI 好酷,然後到了會議室之後剛好大頭(CEO之類的)有來耶! 於是我很興奮的展示了我的提案,然後大頭說:『這好奇怪噢!』,然後我在等著下一句為什麼奇怪,然後然後就沒有了耶。於是這個提案就這樣被幹掉了(我就很落寞的離開了這公司會議室)。其實當初是說要做一個類似 iOS 上的 App 資料夾在桌面上,於是我想說以資料夾為圓心然後把 app icon 散開成環狀,這樣不就是可以讓滑鼠移動距離最小,理論上操作上很順手啊(沒有理論根據,只是我自己分析)。當然後續可能會有些問題,比如說 apps 太多,會把半徑撐太大然後距離又變遠之類。但是我覺得這是小問題,只要固定半徑,然後滾輪或是觸控旋轉 circle 就可以了。硬要抄 apple 總是讓人覺得很反感。更何況用 apple 方式展開 folder 在 24" 螢幕上的話,我要把滑鼠移動多遠才能按到右下角的那個 app 呢?總之,被打槍了,一直到現在我還是不太了解大頭覺得奇怪的點到底是什麼。

剛好那時候 Google+ 推出,Google 把 Circle 的概念實現的很棒,只是可惜 G+ 已經快變鬼城,但這不影響我對 circle UI 的欣賞 :)

到了去年底,Path 2.0 推出,我真的是太欣賞了:

Path 介面上左下角的 circle menu 我真的超愛的,單純是環狀就已經讓我很欣賞了,再加上一些 UI 的理論分析,比如說一般人左手拿手機右手單指操作,那麼觸碰區域的方便性界定大概是這樣:

在 easy 區域裡面是最方便的範圍,所以使用環形剛好可以讓選項都落在 easy 區域中。同時因為選項要第二步才會出現又可以避免為人詬病的 Tab bar 吃掉太多 iPhone 螢幕範圍的問題。不過有利有弊啦,就變成要多一步才可以叫出選項。但是如果以最重要的拍照功能而言,大部份的拍照 App 都是 透過 action sheet :


一樣是要按下 tab 中間的按鈕,然後再從 action sheet 選擇動作,所以就這點看來是還好。 另外有一個問題是有人認為 Path 環狀 menu 太小不好按,這可能就見仁見智了 :)

另外一點很值得提的是, menu 的 animation 實在是做得很好,所以開始出現一堆 open source 來實作這個 menu:

Native Objective-C 版:https://github.com/levey/AwesomeMenu

雖然我還沒能成功地在任何線上產品裡面放進 circle UI ,但我相信有一天我可以實現這個夢,在被認同的情況下實現這個夢(比如做一個圓形螢幕的 Smart Phone 之類的)。

image sources: 
http://www.zurb.com/article/264/outside-in-product-development
http://www.twylah.com/quytennis/tweets/144711624480141312

2012年5月16日 星期三

幫你的網頁加上 backbone(.js) 吧(三)!

今天要帶給大家的是 Backbone.js 的 Router 的使用,這是「幫你的網頁加上 backbone(.js) 吧」 系列的第三集,文章部分取材自於 Joe Zimmerman 的 Javascript Blog 影片教學單元。看影片學寫程式是一件非常棒的事情,但若想快速複習影片中的重點,文字會是更有效率的方式,這也是這系列文章存在的初衷。把影片翻譯成文章不是一件很容易的事,若內容有不夠周詳完整的地方,也懇請多多包涵! 

Router 是 backbone.js 的一個很特別的技術,但並不像 Model 和 View 一樣關鍵,並不是一個必學的項目,因此就算沒有使用 Router 也可以順利做出功能齊全的網頁或 App。

在開始 Router 之前先介紹一下 fragment 的觀念,指的是在一段 URL 當中,緊接在 # (hash tag) 後面的字串(在 RFC3986 當中這段字串叫做分段識別器 Fragment identifier,簡稱 fragment)。例如 http://www.example.org/foo.html#bar 的 bar,就是一個 fragment。

Router 能夠針對不同的 fragment 可以給與相對應的 handler (callback) function,觀念上有點像是 DOM 上的 event listener。因此我們可以針對幾組 fragment 定義被執行或點擊時所要對應到產生的行為,例如讓使用者藉由瀏覽器的「上一頁」或「下一頁」瀏覽同一個頁面內的不同部分且便於觀察瀏覽記錄。

本篇的範例可以到 JSFiddle 取得完整程式碼、瀏覽並練習
環境的基本設定大致上和過去差不多:


最底下可以看到總共有三個超連結,每個 anchor 都對應到一個 fragment,接著,透過 Backbone.Router.extend 來定義這些連結被執行時要對應到的行為。一個簡單的客制化 Router class 可寫成這樣:


第一個屬性 routes 是一個 map,定義了不同的 fragment 的樣式(pattern)所要呼叫的 handler function。

Fragment 的樣式有兩種,一種叫做 parameter parts,另一種叫做  splat parts。每一個 parameter part 會對應到 URL 當中用被斜線 / 隔開的字串。而 splat part 代表的是 # 後面一整串的網址。

在 routes 底下的第一個樣式 ":foo" 表示的是網址內的 # 符號後面的「第一個」字串,而且後面沒有其他的斜線 / 存在。以 http://example.com/#happy 這個例子來說,foo 指的就是 happy,在 http://example.com/#coding 裡,foo 指的就是 coding。而 routes 對應的 handler function "func1" 會因為網址的樣式符合了 ":foo" 而被呼叫,並且會把 foo 的內容當作第一個參數傳進 func1,因此如果網址是 http://example.com/#fun,則 func1 的 p1 值就會是 fun。

因此 ":foo/:bar" 指的是 # 後面被斜線 / 隔開的兩個 fragment 的樣式。以 http://example.com/#page/2 為例子,foo 指的是 page 而 bar 指的是 2, 因此 func2 的兩個參數的 p1 會收到 page,而 p2 會收到 2。
請注意這個樣式並不會呼叫 func1 因為 # 後面又多了一個斜線 / ,因此樣式並不吻合 ":foo"。

第三個樣式 "*action" 的意思是 # 後面的任何字串,不考慮斜線。因此以 http://example.com/#foo/bar/2000 這種網址來說,funcU 這個 handler 拿到的參數 a 就是 foo/bar/2000。

這就是 Router 的貼心設計,連網址變化這種小細節也能很有條不紊地監控,Backbone.js 是不是很方便好用呢?

之後將帶給大家的是陣列版本的 Model 叫做 Collection,敬請期待~

Happy Coding!


延伸閱讀




2012年5月10日 星期四

SEO 幼幼班 (一) - title 的順序

kindergarten

開始做網站之後,發現除了程式之外,還有許許多多要學的部分,SEO 就是其中之一。雖然已經有許多的 blog 對於 SEO 有許多相關的文章,不過就當個記錄吧。這一系列文會記錄一些我所得到跟 SEO 的相關知識,應該都不會是什麼高深的學問,但是我相信會是相當基礎的部份。

前幾天 iCoding 的作者 Tim 考我一個問題,問我說在部落格的文章標題當中,如果部落格名稱是 iCoding,title 標籤當中要用 “iCoding - SEO 幼幼班(一)” 比較好,還是 “SEO 幼幼班(一) - iCoding” 比較好。

先從搜尋引擎的角度來看,在比對關鍵字的時候,會把關鍵字比對在前面 match 的視為比較高度的相關。所以 “SEO 幼幼班(一) - iCoding” 會比 “iCoding - SEO 幼幼班(一)” 來的好,甚至你把 iCoding 拿掉都無妨。

另外就算不從 SEO 角度來看,你可以想像在當你在搜尋引擎找到結果之後,分別看到這兩種結果:

    "SEO 幼幼班(一) - iCoding"
    "iCoding - SEO 幼幼班(一)"

因為人都是由左往右掃過去,所以自然前者可以讓你更快的知道你搜尋到的是什麼東西。更不用說當你 title 裡面的內容更長的時候,第二種的顯示方式可能會看不完所有的內容。

我想這其實對應到的都是同樣的道理,我們做 SEO 的目的是 SEO 關鍵字,重點是在你的網站內容,而不是你的網站名稱,user 想看到的也同樣是你的關鍵字和有關的內容,你的網站內容叫什麼名稱其實一點都不重要。更不用說現在的瀏覽器都支援許多 tab,所以顯示標題的空間也越來越小,把真正重要的標題放在前面才可以讓使用者更容易的看清楚標題。

其實與其說我們在做 SEO,不如說也是為了使用者體驗可以更好著想。因此,當你在想要怎麼樣讓你的網站 SEO 做的更好的時候,或許單純的從怎麼樣讓你的使用者用起來會更順暢開始著手會是個更好的起點。畢竟不管 SEO 做的再好,要是使用者體驗不好那也很難留下人不是嗎。

Reference:
[Blogger]如何對文章標題做SEO優化? - 香腸炒魷魚

2012年5月9日 星期三

Path 網頁設計的細節

一直都很喜歡 Path 的設計,也一直在思考我喜歡 Path 的原因是什麼。不是因為濾鏡,也不是因為 App UI 。是設計上的細節,那一種不重視也不會有關係的細節他們做了,而且還做的很好。於是這細節讓整體設計處處都充滿質感與驚喜啊。



看看這個 Path 在網頁上呈現圖片的版面設計。其實很普通,但很有質感啊,你一定不覺得。我一開始也不覺得。直到我有一天自己做了呈現圖片的頁面,但怎麼看都是庸俗啊。所以我就回來看 Path 到底做了什麼事情可以看起來那麼舒服。原來他加的框不是一般的 border 啊。如果是我做的話,我一定直接加:


然後就會變成這樣 ...

一整個就不立體了啊。

但 Path 是這樣做的:
就只是單純在 img 上面 蓋一層 b 。b 的寬高各少 img 一個 pixel 。然後 b 的 bordr 是 solid 1px rgba(255,255,255,0.3) 。 真的是太聰明了啊。結果就是這麼好看啊:








border 剛好蓋在圖片邊緣上,在加上 alpha 值隱約透出圖片色調。嗯,質感就是這樣來的啊。

這個細節也同時使用在 Path 的 iOS App UI 中。 (可惜 Android 版沒有,難怪總是說 Android 使用者體驗不如 iOS)

--
有興趣的話可以看一下 Path CEO, Dave Morin 的講解影片:http://www.youtube.com/embed/i6exIJaO1iI

2012年5月7日 星期一

幫你的網頁加上 backbone(.js) 吧(二)!

今天要帶給大家的是 Backbone.js 的 View 的使用,這是「幫你的網頁加上 backbone(.js) 吧」 的續集。這一系列的文章取材自於 Joe Zimmerman 的 Javascript Blog 影片教學單元,雖然用影片教寫程式是很棒的一件事情,但是,如果想要快速複習影片中的內容與重點,我相信文字才是最有效率的管道與方式。把影片翻譯成文章不是一件很容易的事,若內容有不夠周詳完整的地方,也懇請多多包涵!

在開始之前,推薦大家使用 JSFiddle,這是一個能讓人一邊看範例程式一邊動手修改,且能立刻看到執行結果的免費服務平台。文中的例子在可以在 http://jsfiddle.net/rightson/xp4pD/ 取得,歡迎多多利用,相信能讓大家看文章的過程更有感覺!

底下的範例希望能讓大家瞭解如何用 Backbone 的 View 和 Model 巧妙搭配,輕鬆寫出 Model 和 View 乾淨抽離的好程式。如果對 Backbone.js 的 Model 原理跟觀念感到陌生的話,也請先閱讀上一個單元之後再繼續往下瀏覽。

我們的目標很簡單:希望在按一下 button 之後,在畫面上印出相對應的內容。


這次除了 Underscore.js 以及 Backbone.js之外,我們還引進了jQuery,請參考底下的原始碼:


接著,讓我們先建立一個簡單的 Model 物件,這物件存著文字(text)和超連結(href)的資料,將會被等一下要建立的 View (template) 拿來使用。

現在要正式進入重頭戲囉:建立 Backbone 的 View 衍生類別。透過呼叫 Backbone.View.extend 這 API ,我們可以傳入客制化的 View 所需要的各種屬性:

initialize 是 View 的建構子,是當 View 物件被建立起來第一時間會執行一次的 method。

el 指的是 View 對應到的 DOM 物件,這個 DOM 上被觸發的 event 都會限制在這 DOM 物件底下被 Backbone.View 捕捉到。
在這例子當中,myView 會監視 '#container' 這個 DOM 物件,任何想監聽的相關 event 都可以被掌握。

events 是非常酷的東西,可以在裡面註冊 el 綁定的 DOM 的 event handler。
直覺的寫法是:

代表的是當 button 的 'click' event 觸發的時候,呼叫 render 這個 method。
也可以寫成:

這表示只要這個 DOM 被 click 就會呼叫 render,很酷吧!

template 是指繪製 View 的時候的一份可套用的 DOM 。
這例子裡面 template 指定給 Id 為 'list-template' 的 DOM 的小孩。我們可以用 jQuery 的 selector 來選出 '#list-template',所以當我們在其他 method 裡寫:

   this.template.clone()

就相當於複製了一份DOM物件出來,例如:


render 是 View 內建的 method,可以透過重新定義 (override) 這個 method 讓我們可以操作改變 el 的外觀。例如把從 model 裡面拿出資料塞入 template,再置換 DOM 的外觀,還有很多種實作的方式,可以參看 Underscore.JS 相關的文件以獲得更深入的瞭解。
在這個例子當中, button 的 click event 會觸發 render,而 render 做的事情就是把塞入資料的「template」 append 到既有的 el 後面:首先透過 this.model.get() 來取出 model 的資料,再用 this.template.clone() 複製一份 DOM,接著透過操作 this.$el (還記得前面提的el 嗎?$el 是用 el 的 jQuery 參照,可以直接當做 jQuery 物件來操作) 把 model 取出來的資料用修改 a 的屬性 (attr 和 text ) 的方式新增一筆 li,然後塞到 el 的最後面。

最後,用剛才繼承的 Backbone View 把 View 物件建出來:

記得指定這個 view 要使用的 model!

讓我們來看看上面的程式跑出來的結果:按下 button 之後會得到底下的結果:


怎麼樣,很簡單易用吧!

到目前為止介紹的的兩個物件 Model 和 View 已經足夠做出大部分的功能囉!
將來還會陸續介紹 Routers 以及 Collection 等稍微進階的物件,相信屆時可以幫助大家寫起來更加靈活輕巧~

Happy Coding!


延伸閱讀




Related Posts Plugin for WordPress, Blogger...