[学习笔记] 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 或从数据库获取)加载的,又该如何将数据更新到页面中?
欲知后事如何,且看下回分解!