[學習筆記] Cordova+AmazeUI+React 作個通信錄 系列文章javascript
目錄
在閱讀了大量 React 的資料(主要是官網)以後,發現有兩個概念很是重要html
Sample Mobile Application with React and Cordova 頁面有一張關於 React 組件的圖,說明了這個 React Demo 應用中各組件的關係(注意觀察線框和箭頭的顏色)。java
Amaze UI React 是在 Amaze UI (jQuery版) 的基礎上,拋棄 jQuery,使用 React 開發的組件庫。Amaze UI React 和 Amaze UI (jQuery版) 共用一套 CSS。react
就從 Amaze 官網的菜單組織也能看到兩者的區別。jQuery 版的菜單包含三項:CSS、JS插件、Web組件;而 React 版就只有一項:組件。所以 Amaze UI 的 React 版再也不須要用戶去了解 CSS 類和過多的腳本操做,只須要關注組件,及其數據(屬性和狀態)便可。jquery
參考文章的通信錄包含列表頁和詳情頁。學習得一步步進行,因此先實現列表頁。git
學習的目標是作一個通信錄,功能和而已都與上圖相似,只是界面改用 Amaze,因此得先去 Amanze UI React 組件文檔頁面 瞭解須要使用的組件,並畫出本身的草圖。數據庫
這個草圖就是最初須要實現的東西:一個頁頭、一個列表、列表項分圖標、文本、圖標按鈕三個部分。而圖標按鈕點擊能夠轉到撥號頁面準備撥號。segmentfault
目標已經清楚了,下面就要開始搭建程序。第一步,先實如今 Nginx 中能正常顯示;第二步再實現構建成 Android 程序在手機上使用(包括顯示和撥號操做)。瀏覽器
以前已經作了很充分的準備,但那主要是對環境的準備。如今立刻要開始寫代碼,不得不作一些細緻的準備,好比,把須要用到的庫安放在代碼中適當的位置。
以前已經肯定了要使用 jQuery,React 和 Amaze UI React。按我我的的習慣,會把它放在 Web 應用的 /libs
目錄下。沒有必要去篩選哪些文件用得上哪些用不上,都拷貝過來,結果就有了這樣的目錄結構
首先就是修改 index.html 文件,在 index.html 中引入須要的 AmazeUI 的 CSS,以及各依賴庫的腳本文件。直接從默認生成的 index.html 改過來就好。
<!doctype html> <html> <head> <meta name="format-detection" content="telephone=no"> <meta name="msapplication-tap-highlight" content="no"> <meta name="viewport" content="user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1, width=device-width"> <title>Concats</title> <link rel="stylesheet" type="text/css" href="libs/amazeui/css/amazeui.min.css" /> <link rel="stylesheet" type="text/css" href="css/index.css"> <script src="libs/jquery/jquery-2.1.4.min.js"></script> <script src="libs/react/react.min.js"></script> <script src="libs/react/JSXTransformer.js"></script> <script src="libs/amazeui/js/amazeui.react.min.js"></script> <script type="text/jsx" src="js/index.jsx"></script> </head> <body> </body> </html>
<body>
標籤中留空,由於以後 React 會將組件渲染在 <body>
中。
<head>
最後引入的 js/index.jsx
就是頁面對應的腳本,使用 JSX 語法以 React 組件的形式實現。通常這個文件是以 .js
做爲擴展名,可是我認爲用 .jsx
做爲擴展名能夠清楚代表該文件中使用了 JSX 語法。
這已是第2次提到渲染了,爲何說 React 渲染,而不說「執行」、「搭建」、「構造」諸如此類的詞呢?先來看看 React 官方是怎麼描述 React 的:
React is a JavaScript library for creating user interfaces by Facebook and Instagram. Many people choose to think of React as the V in MVC.
We built React to solve one problem: building large applications with data that changes over time.
簡單的說,React 是一個構建用戶界面的 JavaScript 庫,它爲構建大型應用而生,這些應用可能隨時產生數據變更。不少人把 React 做爲 MVC 中的 V 來使用。
而在其它文章資料中也提到,React 的處理過程是從數據到視圖的一個單向過程。綜合起來就能夠這樣理解:React 對數據進行渲染,以 UI 的形式呈現。若是數據發生變更,React 會從新進行渲染(實際上 React 會判斷數據變更形成的形式,智能選擇最小渲染範圍以提升效率)。
上面提到將 <body>
標籤內容留空,以便 React 在其中進行渲染。也就是下面這句,React 的渲染入口:
React.render(<Page />, document.body);
上述表達式用了 JSX 語法,而 JSX 中的 X 部分,我理解爲是以 XML 方式描寫的表達式。爲何是表達式,這會在後面的循環中說起。
正如 React 文檔所述,JSX 語法只是一個語法糖,它徹底能夠用純粹的腳原本寫,並且 React 自己也是須要將 JSX 翻譯成 JS 來執行的。上面那句話的純 JS 寫法會是這樣
React.readner(React.createElement(Page), document.body);
那麼 Page
是什麼,這裏看起來它應該是一個合法的 JS 變量——是的,這就是立刻須要定義的 React 組件。
定義組件會使用 React.createClass()
方法。根據對 React 的初步瞭解,我想固然的寫下了一個錯誤的定義
var Header = AMUIReact.Header; var List = AMUIReact.List; // 錯誤的定義 var Page = React.createClass({ render: function() { return ( <Header title="通信錄" /> <List /> ); } }); React.render(React.createElement(Page), document.body);
個人原意是但願能定義 <Page />
組件,並將其渲染在 <body>
中,只要能顯示頁頭就行,列表部分暫時留空。
然而經過 Nginx 跑出來以後,從瀏覽器的控制檯獲得了一個錯誤消息
Uncaught Error: Parse Error: Line 13: Adjacent JSX elements must be wrapped in an enclosing tag
大概意思是說,JSX 的元素必須是1個封閉的標籤。這裏提供了兩個要素:「1個」、「封閉」。因此我根據這個意思,修改了一下,而後運行出了預期的效果。
render: function(){ return ( <div> <Header title="通信錄" /> <List /> </div> ); }
上面的代碼中,var Header = AMUIReact.Header
和 var List = AMUIReact.List
是 Amaze UI React 教程示例中演示的用法——爲帶命名空間的組件建立簡短的名稱。其實我更傾向於使用帶命名空間的名稱,就像 <AMUIReact.Header title="通信錄" />
。這能夠避免自定義組件和 Amaze UI React 組件的名稱衝突。不過 Amaze UI React 定義的這個命名空間太長,能夠本身縮短一下,好比
var A = AMUIReact;
<A.Header title="通信錄" />
後面的示例中就採用這種縮短命名空間的寫法。
參考
ReactClass createClass(object specification)
根據參數提供的規格說明,建立組件類。規則說明是一個 JavaScript 對象,其提供的 ReactElement render()
函數會返回一個 ReactElement
(對象)用於渲染。render()
中返回的 ReactElement 能夠是 JSX 描述,也能夠是純 JS 腳本。上面的例子是用的 JSX 描述,若是改爲 JS 腳本,應該像這樣
render: function() { return React.createElement("div", {}, [ React.createElement(Header, { title: "通信錄" }), React.createElement(List) ]); }
很明顯,JSX 描述更清晰易讀也更容易寫出來。
()
包起來的,其實若是不包起來也不會出錯。但很顯然,在寫 JavaScript 程序的時候,若是 return 的內容是多行,用括號包起來是個好習慣。如今繼續下一步,添加列表項。在沒搞清楚如何使用循環以前,仍是先用重複的代碼把列表項顯示出來再說——固然,在目前沒有定義數據結構的狀況下,也不會用到循環。考慮到對組件還不夠熟悉,列表項的內容,暫時僅展現姓名。
// js/index.jsx var A = AMUIReact; var Page = React.createClass({ render: function() { return (<div> <A.Header title="通信錄" /> <A.List> <A.ListItem> 張三 </A.ListItem> <A.ListItem> 李四 </A.ListItem> <A.ListItem> 王麻子 </A.ListItem> </A.List> </div>); } }); React.render(React.createElement(Page), document.body);
這個結果並很差看,但至少已經實現了列表的顯示。待功能完善以後還不能達到滿意的效果,能夠自定義 CSS 來調整,因此不急。
數據固然不會是固定不變的,直接將列表項寫死很是不切合實際。在學習初期,我暫時還不想去和數據庫打交道,因此暫時用 JSON 來保存數據,並且爲了保持獲取數據不節外生枝,先把數據定義在 index.jsx 的最前面。
// js/index.jsx var data = [ { "name": "張三", "tel": "13801234567" }, { "name": "李四", "tel": "18018001800" }, { "name": "王麻子", "tel": "17098765432" } ]; var A = AMUIReact; // ... 後面的代碼略
而後改 render()
,想固然的又寫了個段錯誤代碼
// 錯誤的代碼 render: function() { return (<div> <A.Header title="通信錄" /> <A.List> for (var i = 0; i < data.length; i++) { <A.ListItem>{data[i].name}</A.ListItem> } </A.List> </div>); }
這回從錯誤消息中能夠發現是 for
循環惹的禍。一開始不明白爲啥,仔細思考以後明白了——return
後面的應該是一個表達式,而 for
循環不是表示式。因而嘗試把 for
語句改爲 Array.prototype.map()
方法
render: function() { return (<div> <A.Header title="通信錄" /> <A.List> {data.map(function(t) { return ( <A.ListItem>{t.name}</A.ListItem> ); })} </A.List> </div>); }
這回是對了,可是這寫法看起來不夠簡潔,容易把人搞暈。參考網上的資料,發現能夠將 map()
的結果保存在一個變量中,再在 <A.List>
中引用
render: function() { var items = data.map(function(t) { return <A.ListItem>{t.name}</A.ListItem>; }); return (<div> <A.Header title="通信錄" /> <A.List> {items} </A.List> </div>); }
小結 JSX 中若是在代碼中嵌入成對的
<XML標籤>
,會被翻譯成組件代碼(React.createElement(...)
等),而在 xml 標籤中使用一對大括號{}
能夠嵌入 JS 代碼。若是對 ASP.NET MVC 的 Razor 模塊有所瞭解,就會有似曾相識的感受。
接下來還要爲列表項添加圖標,以 React 的組件化思惟來思考,比較好的做法是定義一個組件,不妨叫 Person
來封裝圖標、姓名和電話按鈕。那麼,如何將每一個人的數據傳入 Person
對象?
另外,把數據放在 index.jsx 中也不是個辦法,早晚仍是得用異步(好比 Ajax 或從數據庫獲取)加載的,又該如何將數據更新到頁面中?
欲知後事如何,且看下回分解!