本文源代码可以在这里找到

如果你有成为全栈的梦想,METEOR是个不错的平台。


2.使用React Components定义视图(Defining views with React components)

我们把React用作视图库,让我们增加一些NPM packages让我们能使用React进行开发。打开一个新的terminal在你的App根目录下,键入以下命令:

  1. meteor npm install --save react react-dom

替换初始化的代码

在开始前,我们要替换创建App时的初始代码。接着我们讨论要做些什么。

第一步,替换初始化的HTML中的内容:

  1. <head>
  2. <title>Todo List</title>
  3. </head>
  4. <body>
  5. <div id="render-target"></div>
  6. </body>

第二步,删除client/main.js,并创建三个新文件:

  1. // ./client/main.jsx
  2. import React from 'react';
  3. import { Meteor } from 'meteor/meteor';
  4. import { render } from 'react-dom';
  5. import App from './imports/ui/App.jsx';
  6. Meteor.startup(() => {
  7. render(<App />, document.getElementById('render-target'));
  8. })
  1. // ./imports/ui/App.jsx
  2. import Reacr, { Component } from 'react';
  3. import Task from './Task.jsx';
  4. //App组件 —— 代表整个App
  5. export default class App extends Component {
  6. getTasks() {
  7. return [
  8. { _id: 1, text: 'This is task 1' },
  9. { _id: 2, text: 'This is task 2' },
  10. { _id: 3, text: 'This is task 3' },
  11. ];
  12. }
  13. renderTasks(){
  14. return this.getTasks().map.((task) => {
  15. <Task key={task._id} task={task} />
  16. });
  17. }
  18. render(){
  19. return (
  20. <div className="container">
  21. <header>
  22. <h1>Todo List</h1>
  23. </header>
  24. <ul>
  25. {this.renderTasks()}
  26. </ul>
  27. </div>
  28. );
  29. }
  30. }
  1. // ./imports/ui/Task.jsx
  2. import React, {Component, PropTypes} from 'react';
  3. // Task组件 —— 代表一个单独的todo条目
  4. export default class Task extends Component {
  5. render(){
  6. return (
  7. <li>{this.props.task.text}</li>
  8. );
  9. }
  10. }
  11. Task.propTypes = {
  12. //这个组件通过React prop去得到并显示任务
  13. //我们可以用propTypes去指明哪些是必须的
  14. task:PropTypes.object.isRequired,
  15. }

我们仅在我们的App中做了3件事:

  1. 一个App React component

  2. 一个Task React component

  3. 一些初始化代码(在client/main.jsx客户端JavaScript入口文件中),在Meteor.startup代码块中,我们知道当页面加载完毕后会执行里面的代码。这段代码加载其他组件,并渲染#render-target元素。

你还可以在Application Structure article中了解import是如何工作的,还有如何组织你的代码。

在接下来的教程中,我们增加或更改代码,都会涉及到这些组件。

检查结果

在浏览器中,我们的app应该看起来像这个样子:

Todo List

  • This is task 1

  • This is task 2

  • This is task 3

如果你的app看起来不是这样,可以去GitHub下载代码,并和你自己的代码对比,找出不同的地方。

HTML文件定义静态内容

Meteor会解析你app目录下的所有HTML文件,并识别三个顶级标签<head>,<body><template><head>标签内的所有内容会发送到客户端HTML的head标签,<body>标签内的所有内容也会发送到客户端HTML的body标签内,就和正常的HTML文件一样。

任何<template>标签内的内容会编译成Meteor Templates,你可以在HTML中用{{>templateName}}去调用,或在JavaScript中用Template.templateName去调用。在这个教程中,我们不会用到Meteor提供的模板特性,因为我们将用React去定义所有视图组件。

用React定义视图组件

在React中,视图组件是React.Component的子类(当我们用import { Component } from 'react'的方式引入时)。你可以自由的在组件上添加方法,但有几个特殊的方法是不行的,比如render方法。组件通过其父组件的props属性,也可以接收数据。在这个教程中,我们会重温一些React的通用特性。你也可以查看React官方教程

重新审视JSX中的render方法

在每个React Component中最重要的方法就是render(),它会访问React并得到被描述的HTML,然后把组件显示出来。这个HTML内容用JavaScript扩展语法写成,叫JSX,他看起来像写HTML一样去写JavaScript。你可以看到一些显而易见的差异:在JSX中,你要用className去代替class属性。还有一件很重要的事,它不是像Spacebars和Angular一样的模板语言,实际上它是直接编译成正常的JavaScript。查看更多JSX的信息

JSX支持ecmascript扩展包,所以它默认支持所有Meteor app的扩展包。

  1. /*./client/main.css*/
  2. body {
  3. font-family: sans-serif;
  4. background-color: #315481;
  5. background-image: linear-gradient(to bottom, #315481, #918e82 100%);
  6. background-attachment: fixed;
  7. position: absolute;
  8. top: 0;
  9. bottom: 0;
  10. left: 0;
  11. right: 0;
  12. padding: 0;
  13. margin: 0;
  14. font-size: 14px;
  15. }
  16. .container {
  17. max-width: 600px;
  18. margin: 0 auto;
  19. min-height: 100%;
  20. background: white;
  21. }
  22. header {
  23. background: #d2edf4;
  24. background-image: linear-gradient(to bottom, #d0edf5, #e1e5f0 100%);
  25. padding: 20px 15px 15px 15px;
  26. position: relative;
  27. }
  28. #login-buttons {
  29. display: block;
  30. }
  31. h1 {
  32. font-size: 1.5em;
  33. margin: 0;
  34. margin-bottom: 10px;
  35. display: inline-block;
  36. margin-right: 1em;
  37. }
  38. form {
  39. margin-top: 10px;
  40. margin-bottom: -10px;
  41. position: relative;
  42. }
  43. .new-task input {
  44. box-sizing: border-box;
  45. padding: 10px 0;
  46. background: transparent;
  47. border: none;
  48. width: 100%;
  49. padding-right: 80px;
  50. font-size: 1em;
  51. }
  52. .new-task input:focus{
  53. outline: 0;
  54. }
  55. ul {
  56. margin: 0;
  57. padding: 0;
  58. background: white;
  59. }
  60. .delete {
  61. float: right;
  62. font-weight: bold;
  63. background: none;
  64. font-size: 1em;
  65. border: none;
  66. position: relative;
  67. }
  68. li {
  69. position: relative;
  70. list-style: none;
  71. padding: 15px;
  72. border-bottom: #eee solid 1px;
  73. }
  74. li .text {
  75. margin-left: 10px;
  76. }
  77. li.checked {
  78. color: #888;
  79. }
  80. li.checked .text {
  81. text-decoration: line-through;
  82. }
  83. li.private {
  84. background: #eee;
  85. border-color: #ddd;
  86. }
  87. header .hide-completed {
  88. float: right;
  89. }
  90. .toggle-private {
  91. margin-left: 5px;
  92. }
  93. @media (max-width: 600px) {
  94. li {
  95. padding: 12px 15px;
  96. }
  97. .search {
  98. width: 150px;
  99. clear: both;
  100. }
  101. .new-task input {
  102. padding-bottom: 5px;
  103. }
  104. }

添加上面的CSS代码到你的项目中,这个首页看起来会很棒。在你的浏览器中检查样式是否加载进去了。

上一节:Creating an app(创建一个APP)

下一节:Collections(集合)