项目

·#你的第一个Meteor应用

项目刚开始学习如何编制Web应用的开发者的一个大错误是在对要创建的东西还没有一个清淅的认识时就开始进行。但这就像开车去一个新的目的地却没有地图。你可能会在正确的方向有一个小的进展,但你可能不会到达你需要去的地方。你不需要从一开始就知道一切,但你的确至少需要一个方向。

记住这一点,我们要构建Leaderboard(排行榜)——Meteor开发团队设计的一个示例应用程序展示Meteor用很少的几行代码能做什么。 这就是它看起来的样子: Leaderboard已经在官网上已经被更高级的例子取代了,但它会是我们的示例项目,主要有两个原因: 首先,这个应用程序已经存在。我们可以玩,这意味着我们可以在我们编写单行代码前对我们试图创建的应用有一个好的认识。 第二,应用程序很简单。这意味着我们不需要担心构建软件的概念(这通常是最困难的一部分)。相反,我们可以集中学习Meteor本身。 要获得实际的时间和排行榜,请访问leaderboard2.meteor.com,点击,注意其核心特征:

  • 有玩家的列表。
  • 每个球员都有一个分数。
  • 球员得分排名。
  • 你可以选择玩家通过点击它们。
  • 你可以增加一个选择球员的得分。 在后面的章节中我们将创建附加功能,但即使相对较短的列表也涉及许多Meteor的核心功能。

创建一个项目创建我们的第一个Meteor应用程序,我们将需要创建我们的第一个项目,一个项目是一组自包含的文件表单应用程序的基础。您可以使用单词

“project”和“application”互换使用,但在谈到被开发的应用时“project”会更合适。 每个项目都是不同的,但是一般会包含:

  • HTML文件,创建接口。
  • CSS文件,指定样式的界面。
  • JavaScript文件,定义应用程序逻辑。
  • 文件夹,确保都是组织良好的。 一个项目可以包含其他类型的文件,如图片和CoffeeScript文件,但在这本书中我们会尽可能保持简单,只展示我们需要的。 在我们创建Leaderboard应用项目前,让我们创建一个文件夹来存储我们的Meteor项目。我们不是必须这样做,但为了保持的东西 有条理,这是一个好主意。 当然,我们可以选择“新建文件夹”选项从“文件”菜单,但这哪儿有乐趣?相反,输入以下命令行:
1 mkdir Meteor
然后点击“回车”键。 使用mkdir命令创建一个文件夹。这mkdir命令代表“目录”,从这个名字你可能猜到,它允许我们做出一个目录。 在这个实例中,我们创建一个名为“Meteor”的目录,但是您可以调用任何你想要的文件夹。的精确位置的文件夹就会出现将取决于你操作系统,但至少在Mac OS X上,将出现在“家”的文件夹目录 默认情况下。(如果你找不到文件夹,创建简单的搜索你的电脑。) 一旦准备好了目录,导航到它使用下面的命令:
1 cd Meteor
cd命令代表“改变目录”命令行相当于在图形界面中双击一个目录,按下“回车”键后,我们将在“Meteor”目录。 导航到“Meteor”文件夹。 然后在这个目录中创建一个Meteor项目,运行如下命令:
1 meteor create leaderboard
这个命令有三个部分: - meteor部分定义这是一个meteor命令。 - create部分澄清,我们想创建一个meteor项目。 - leaderboard的部分是我们分配给项目的名称。 运行此命令后,会出现一个“leaderboard”目录内的“meteor”文件夹,默认情况下,该文件夹将包含三个文件: - leaderboard.html - leaderboard.css - leaderboard.js 它还包含一个隐藏文件夹.meteor,但如果您的操作系统从视图中隐藏了这个文件夹,这很好。我们不会碰它。 在我们的项目的文件夹 ### 本地服务器Web应用程序不像静态网站。我们不能只是打开leaderboard.html文件就奇迹的看到一个动态的Meteor的动态应用程序。事实上,如果我们在Chrome浏览器打开该文件,所有我们会看到的是一些静态文本: 没有什么动态。 要得到我们计划中的web应用程序,我们需要启动所谓的本地服务器。这是一个web服务器,在我们的本地机器上运行。它包含在Meteor中并允许 我们:
1 2 1.看到我们的JavaScript代码的处理结果。 2.在我们的本地机器上运行一个数据库。
如果你使用一个应用程序像MAMP部署PHP和MySQL,这将是熟悉,但如果这一切听起来可怕,不要害怕。在实践中,这很简单。 通过命令行中,导航到“leaderboard”目录中:
1 cd leaderboard
然后输入以下命令:
1 meteor run
这里,meteor的部分定义了这是一个meteor命令,run部分阐明了我们要采取的精确行动。在这种情况下,我们想要运行本地服务器。 启动本地服务器。 利用“回车”键后,将显示如下:
1 2 3 4 =>Started proxy. =>Started MongoDB. =>Started youApp =>running at: http://localhost:3000/r app.
这些线确认本地服务器启动和URL的最后一行- [http://localhost:3000——是我们现在可以使用项目在web浏览器中查看我们的Meteor。](http://localhost:3000——是我们现在可以使用项目在web浏览器中查看我们的Meteor。) 导航到该URL在Chrome和注意,我们不再看到静态文本。相反,我们看到一个功能的web应用程序。应用程序本身是代码的结果这是包含在每个流星项目默认情况下,这并不是最有趣的创造在世界上,但是我们仍然在正确的方向上迈出了一步。 这是默认的流星的应用程序。 不断地查看代码的结果,我们需要保持本地服务器运行。这个简单的 那就意味着要离开命令行打开从这一点开始。然而,您将需要打开 一个单独的标签或窗口进一步写命令: 一个单独的运行命令的选项卡。 在本地服务器停止,要么退出命令行,或命令行焦点, 项目22 在你的键盘上按CTRL + C。然后再次启动本地服务器,使用相同的命令 之前: 流星跑 只要确保你在一个项目的文件夹在运行命令之前。 项目23 默认应用程序 默认应用程序没有什么特别的,但是如果我们点击“点击我”按钮,这个号码 在屏幕上就会增加。这提供了一个相当普通的流星的实时演示 特性。这个应用程序背后的代码,但是,不正是重要的因为我们将讨论 在接下来的章节更大范围。 目前,打开项目文件和删除所有的默认代码。甚至不看看 代码。刚刚摆脱它。我们想要从一个完全空白。 一旦完成,在JavaScript中输入以下文件: 控制台。日志(“Hello world”); 然后保存文件并打开JavaScript控制台在铬: 1。单击视图菜单。 2。悬停在开发人员选择。 3所示。选择JavaScript控制台选项。 窗格的底部将打开浏览器并显示“Hello world”我们的文本 通过控制台。日志语句。 “Hello World”的文本出现在JavaScript控制台。 项目24 如果这是熟悉的,很好。如果不是,那么知道控制台。日志语句用于看到输出结果 不创建一个接口的代码显示输出。这意味着,在我们投资 时间为创建一个接口,我们可以: 1。确认我们的代码是按预期工作。 2。尽快修复任何错误出现。 我们还可以使用控制台操作应用程序的数据库,这是我们要做的 下一章。 离开控制台打开从这一点开始,但是随时删除控制台。日志语句 在JavaScript文件。 项目25 总结 在这一章,我们了解到: •当学习如何构建一个web应用程序,重要的是要有一个清晰的认识 你想构建。 •命令行可以用来迅速达到熟悉的任务,如创建文件夹和 他们之间导航。 •开发流星应用程序时,我们将它作为一个“项目”,我们可以创建一个 项目与流星创建命令。 •来查看我们的web应用程序在本地机器上,我们可以用流星运行命令 启动一个本地web服务器。 •当结合控制台。日志语句,JavaScript控制台是一个非常方便的工具 流星发展。 流星的更深层次的理解: •如果你还没有,玩耍与原排行榜的应用程序。它不 有很多功能,但这只是意味着没有理由不是有很强的把握的 它的功能。 •关闭命令行应用程序,然后重新打开它,回到你在哪里。 你应该能够浏览到您的项目的文件夹cd命令启动 本地服务器与流星跑。 •创建第二个流星项目和使用这个项目尝试当你学习 一些新的东西。折腾了为了这是一个很好的方式钻细节 深入你的大脑。 在其当前状态查看代码,查看GitHub提交。 数据库中,第1部分 写一个技术书的一个困难的部分是决定何时引入某些想法。 需要教的主题书之间是一致的,但你说的顺序 他们可以大大影响读者理解某些内容的能力。 例如,往往技术作者尽可能谈论创建一个接口 尽快这是因为看到很有趣的视觉结果代码,和很高兴的感觉 像你做出了很快的进步。 但是这种方法并介绍一下几个问题: 1。很难掌握任何有关前端(接口)当你没有 熟悉后端(数据库,等等)。 2。如果我们首先谈论的前端,我们将不得不回顾在下一章,所以任何 快速进步的感觉将是短暂的。 因此,我们将首先讨论我们的项目内创建和管理数据库。这 不是一个“性感”的话题,但是如果我们花几分钟覆盖基础,我们将有一个强大的 本书的其余部分的基础。 26 第1部分数据库,27岁 MongoDB vs . SQL 如果您已经构建了一些之前在网上,你可能接触到 的数据库。也许你安装WordPress的副本,或使用phpMyAdmin,甚至建造 一些软件语言像PHP。在这些情况下,您会接触到 一个SQL数据库。 默认情况下,每个流星项目有自己的数据库。没有安装或配置 必需的。当你创建一个项目时,会自动创建一个数据库项目,和 当本地服务器正在运行,那么数据库。然而,这个数据库并不是一个SQL 数据库。相反,它是所谓的MongoDB数据库。 如果你之前从未遇到MongoDB,你可能会有点担心,但不要害怕。蒙戈 数据库和SQL数据库不同,但是作为初学者而言,差异 很小。 目前,你只需要知道两件事: 首先,没有其他类型的数据库用于流星。如果你想使用一个SQL 数据库,例如,它是不可能的。其他选项可以在未来,但是 时间其实还不清楚。 第二,蒙戈使用不同的词汇来描述熟知的概念。例如,我们不会 使用“表”和“行”这样的词,但概念基本上是相同的。你可以看到 这个表的差异: MongoDB vs . SQL 会很难想起概念熟悉新单词,但是我将提供大量的提醒 通过这本书我们进步。 第1部分数据库,28 创建一个集合 排行榜的中央功能应用程序的列表的球员。没有球员的名单 出现在界面,我们不能建立其他任何有价值的物品。因此这是一个好地方 开始——从应用程序的“中间”,向外工作的细节。 这里有两个问题需要考虑: •我们在哪里存储与每个玩家相关的数据? •我们如何显示这些数据从内部接口? 我们将在下一章回答第二个问题,但第一个问题:“在哪里 我们与每个球员关联存储数据吗?” 滑稽的答案将是“数据库”,但更有用的答案” 收集”,如前一节所示,相当于一个SQL表集合。 为了说明的目的收集,想象我们正在创建自己的版本的WordPress 流星。如果是这样的话,我们会创建一个集合的文章,为集合 评论,和一组页面。我们会创建一个为每个类型的数据收集。自 我们创建这个排行榜的应用程序,我们将创建一个集合的球员。 要做到这一点,打开JavaScript文件,写如下声明: 新的Mongo.Collection(球员); 在这里,我们创建一个集合命名为“玩家”在我们项目的Mongo数据库。你可以 名字收集任何你想要的,但它必须是唯一的。如果名字不是独一无二的,流星 将返回一个错误。 尽管这行代码,我们还没有供我们参考这个集合定义了一个方法, 因此我们没有办法操作。 为了解决这个问题,将集合在一个变量: PlayersList = new Mongo.Collection(球员); 但请注意,我们没有使用var关键字,因为我们想要创建一个全球性的 变量。这将允许我们引用和操作在我们所有的集合 项目的文件。 确认收集存在,保存文件,切换到Chrome浏览器,并输入的名称 集合的变量为控制台: PlayersList 第1部分数据库,29岁 您应当会看到类似如下: 集合的存在。 这表明集合是按预期工作。 如果返回一个错误,这可能是因为你的名字输入错误变量在控制台, 或在代码中犯了一个语法错误。 数据库中,第1部分30 插入数据 当我们想将数据插入一个集合,我们有四个选项。我们可以通过插入数据 JavaScript控制台,通过命令行,通过JavaScript文件,并通过 形式的界面。我们将看到如何使用所有这些选项在这本书,但第一 选项-通过JavaScript控制台是最简单的,所以这是最好的起点。 在控制台中,写如下: PlayersList.insert(); 这是我们使用的语法来操纵一个集合。 我们开始分配给变量集合,然后——“PlayersList”变量 附加功能。在本例中,我们使用插入函数,但是有一个范围的 功能,如查找、更新和删除(和我们将讨论这些很快的细节)。 但是,如果我们把“返回”键在这一点上,没有什么会发生,那是因为我们 需要在函数的括号之间传递数据改变的内容 集合。 我们通过的数据需要以JSON格式,如果你不熟悉 JSON格式,这就是它的样子: { 名称:“大卫”, 得分:0 } 在这里,有几个事情: 首先,数据是用一对大括号。这就是我们如何区分我们的JSON数据 剩下的代码。 第二,我们已经定义了一对密钥。这些键被称为名字和分数,蒙戈 术语,这些是我们收集的字段。因为每个球员将集合 有一个名称和一个分数,名字和分数字段来保存这些值。 第三,我们已经定义了与我们的键相关联的值。在这种情况下,价值的名字 字段是“大卫”和分数字段的值是0。 第四,键值用逗号隔开。这是因为JSON格式 忽略空白,所以逗号是需要提供结构。 我们可以通过这些数据通过括号,像这样: 第1部分数据库,31日 PlayersList.insert({ 名称:“大卫”, 得分:0 }); 这是一个完整的插入功能,如果我们这个语句输入到控制台和挖掘 “返回”键,将会创建一个文档在“PlayersList”集合。文档是 相当于SQL行和,在这一点上,我们要为每个玩家创建一个文档 希望在我们的集合。如果我们希望我们的排行榜包含六名球员,我们需要使用 六次插入函数,从而创建6个文档。 插入数据。 为了实现这一点,重复这句话几次,确保定义独特的值 名称字段,所以我们可以区分球员: PlayersList.insert({ 名称:“鲍勃”, 得分:0 }); 由于忽略空白,语句可以写在一行: PlayersList。插入({ name:“鲍勃”,得分:0 }); 数据库中,第1部分32 也请注意,创建每个文档后,会出现一个随机的数字和字母 在控制台。这种混乱的局面是一个独特的ID MongoDB和自动创建的 与每个文档相关联。它的主键,它会是重要的。 目前,只注意到它的存在所以你不惊讶当我们讨论一遍。 在我们继续之前,更多的玩家插入集合。示例应用程序 六名球员,应该够了。 球员们在我的名单是: •大卫 •鲍勃 •玛丽 •比尔 •沃伦 •蒂姆 他们都有得分字段设置为0。 将剩下的球员。 第1部分数据库,33 找到数据 现在,我们有一些数据收集,我们能够检索这些数据。我们将这样做 接口在下一章,但就目前而言,我们只是通过控制台。 在控制台,输入以下: PlayersList.find(); 在这里,我们使用这个找到函数,用于检索数据从指定的集合。 因为我们没有任何穿过支架,该语句将检索所有的 的数据集合。 以下应该出现在控制台: 使用find函数。 但很明显,这不是最可读的回应。我们的应用程序可以是有意义的,但是 我们不能。 检索数据更可读的格式,附加一个获取函数的转换 检索到的数据转换成一个数组: .fetch PlayersList.find()(); 第1部分数据库、34 您应该看到如下: 使用查找和获取功能。 我们也可以单击下箭头与每个文档相关的数据, 包括: •_id字段,存储文档的惟一的ID(“主键”,我们 之前提到过)。 •名称字段,存储的球员的名字。 •比分字段,存储得分的球员。 但是如果我们想要检索的数据的集合,而不是所有的 数据?要做到这一点,我们可以通过json格式的数据之间的括号: PlayersList。找到({ name:“大卫”}).fetch(); 这里,我们通过字段名和值通过发现功能,因此,我们可以 只检索文档,球员的名字字段等于“大卫”。在我们的例子中,这个 只检索一个文档,但是如果我们集合包含多个玩家叫“大卫”, 他们都是根据这个查询返回。 也有用的是计算能力的数量由一个查询返回的文件 将计数函数找到函数: 数据库中,第1部分35 .count PlayersList.find()(); 因为这个语句将计数集合中的所有文档,如果有六名球员 (文件)的集合,6号返回。 第1部分数据库、36 总结 在这一章,我们了解到: •当我们创建一个流星项目,蒙戈数据库自动创建,和 当本地服务器正在运行,那么数据库。 •Mongo数据库和SQL数据库不同,但差异是无关紧要的 初学者而言。 •为每一种类型的数据需要存储在Mongo数据库中,我们需要创建一个集合。 集合包含文档和文档的字段和值。 •使用插入函数,我们可以将数据插入一个集合。这个数据结构 以JSON格式。 •通过使用find函数,我们可以从集合中检索数据。这些数据就可以 通过使用控制台导航。 流星的更深层次的理解: •注意,我们还没有预定义的数据库的结构。相反,结构 定义数据库的动态,我们使用插入函数。 •在一个单独的项目中,创建一个存储不同类型的数据的集合,比如博客 帖子,也许。什么样的字段集合有吗? 在其当前状态查看代码,查看GitHub提交。 模板 在这一章,我们将开始构建排行榜的用户界面的应用程序。 这包括创建我们的第一个模板。 首先,下面的代码在排行榜。html文件: <头> <标题>排行榜< /名称> < / >头 <身体> <标题>排行榜< / h1 > < /身体> 这段代码没有什么特别之处——它只是标准的HTML,但出现 缺少几件事: •我们没有包含html标签。 •我们还没有包括任何JavaScript文件 •我们还没有包括任何CSS文件。 但是我们没有包括这些事情,因为我们不需要他们。流星负责 对我们这些细节。它将html标记添加到文件的开始和结束,自动 包括项目的文件夹中包含的任何资源(比如JavaScript和CSS文件)。 这不是世界上最引人注目的特性,但是流星的核心理念之一 开发者幸福,所以有很多这样传遍了节省时间的特性 框架。 37 模板38 创建一个模板 模板用于创建接口和JavaScript代码之间的连接。当 我们把界面元素在一个模板,我们可以参考和操作 元素与应用程序逻辑。 创建一个模板,将下面的代码添加到HTML文件的底部,下 关闭body标签: <模板名称=“排行榜”> Hello World < /模板> 在这里,我们使用这个模板标签,它使用一个名称属性来区分 我们创建不同的模板。在这种情况下,模板的名称是“排行榜”,我们会 很快这个名字从JavaScript文件的引用。 如果你保存文件在其当前状态,模板不出现在web浏览器。 在HTML文件,但是没有别的地方了。这是因为,在默认情况下,模板不出现 内部接口。这听起来可能很奇怪,但是考虑到,在某些情况下: •您可能希望一个模板出现在某些时候。 •您可能希望一个模板在某些时刻消失。 •你可能想要一个模板出现在多个位置。 考虑到这种可能性,我们需要手动包含模板内部的接口。这 确实需要一个额外的步骤,但它会变得越来越有用,因为我们深入发展。 使“排行榜”模板出现在浏览器内,把这个标签之间的身体 需要在HTML文件: { { >排行榜} } 显然,这不是HTML。代替。double-curly括号的使用意味着这是空格键 语法,空格键是语法中我们使用HTML当我们想要动态 发生。这是语法,桥梁之间的差距接口和应用程序逻辑。 我们将了解更多关于空格键在这本书,但现在,知道: 1。所有空格键标签使用double-curly括号来区分。 2。我们只使用大于符号当我们想要包括一个模板。 基于这些变化,HTML文件现在应该类似于: 模板39 <头> <标题>排行榜< /名称> < / >头 <身体> <标题>排行榜< / h1 > { { >排行榜} } < /身体> <模板名称=“排行榜”> Hello World < /模板> 保存文件之后,内部的“Hello World”从“排行榜”模板 出现在浏览器: 当前界面。 模板40 客户端与服务器 在我们继续之前,我想要证明的东西。你不需要完全理解我们 封面,但都遵循允许通过编写的所有代码。 在JavaScript文件,编写以下控制台。日志语句: 控制台。日志(“Hello world”); 这是我们声明语句写在“项目”一章,并在保存文件 切换回Chrome,您应该看到“Hello world”消息出现在控制台: “Hello World”出现在控制台。 上次我没有提到虽然是,由于这种说法,别的东西也 发生,如果我们切换到命令行中,我们可以看到“Hello world”消息 也在这里: 模板41 “Hello World”出现在命令行。 这是很重要的,因为我们已经写一行代码的执行在两个地方。的 代码是运行在客户端(在用户的web浏览器)和服务器(其中 应用程序托管)。 为什么这很重要? 有几个原因,但这里有一个例子: 自从我们创造了“PlayersList”集合,下面的语句上运行 客户端和服务器: PlayersList = new Mongo.Collection(球员); 但是代码不做同样的事情在这两个地方。 当代码在服务器上执行,创建在Mongo集合数据库。这是 我们的数据存储。当代码执行从用户的web浏览器中虽然- 在客户端创建一个本地副本的收集用户的计算机。作为一个结果, 当用户与数据库交互时,他们实际上交互的本地副本。这 部分原因是流星应用程序默认是实时的。数据是用户的操作 本地机器然后无形在后台与服务器端数据库同步。 但如果这一切听起来有点概念,不要害怕。你不需要了解细节 点流星的“魔法”。你只需要一行代码就可以掌握: 1。在两个不同的环境中运行(在客户端和服务器)。 模板42 2。根据不同的环境会有不同的行为。 也就是说,在某些情况下,我们不希望我们的代码运行在两个地方。如果, 实例中,我们编写代码,只会影响应用程序的接口,它不会是有意义的 在服务器上运行的代码。我们只希望它在客户机上运行。 适应,有一双条件我们可以用来确定代码运行 的环境。你会有一个更好的想法何时使用这些条件 通过书的进展,但是,只要跟着目前通过编写所有的 代码。 首先,一颗流星。isClient条件下的控制台。日志声明: 如果(Meteor.isClient){ / /这段代码只在客户机上运行 } 这个条件允许我们专门执行代码在客户端——从用户的内部 web浏览器,为了证明这一点,我们可以简单地添加一个控制台。日志声明内 条件: 如果(Meteor.isClient){ 控制台。日志(“你好客户”); } 保存文件,切换到浏览器,注意,“你好”客户端消息出现在 控制台,但没有出现在命令行里面。这是因为代码没有被 在服务器上执行。 模板43 “你好,客户端”只出现在控制台。 我们可以创建与流星相反的效果。isServer条件: 如果(Meteor.isServer){ / /这段代码只运行在服务器上 } 再次,我们将放置一个控制台。日志语句内部条件: 如果(Meteor.isServer){ 控制台。服务器日志(“你好”); } 保存文件之后,请注意,“你好”服务器消息出现在命令 线,但不出现在控制台。这是因为只有被执行的代码 托管服务器(应用程序)。 模板44 “你好,服务器”只出现在命令行。 但是如果这一切都是真的沉没,只要记住两件事: 1。一行代码可以运行在客户端和服务器。 2。有时我们不想让我们的代码运行在这两个地方。 精确的时刻,我们需要考虑这些点很快就将变得明朗了。 现在,仅仅删除控制台。日志语句,但离开他们的条件。我们会 很快就会使用它们。 模板45 创建一个助手 在这一点上,我们的“排行榜”模板只显示静态文本“Hello World”。为了解决这个问题, 我们将创建一个helper函数,一个辅助函数是一个常规的JavaScript函数 附加的模板,让我们从一个接口内部执行代码。 开始,我们将一个古老的方法来创建辅助函数。这种方法已被弃用, 这意味着它不再是官方支持,你读这句话的时候,它可能 不工作。但这老格式更容易教和理解,并允许我们来缓解 到non-deprecated方法,我们会讨论。 在JavaScript文件,编写以下isClient内部条件: Template.leaderboard.player 这是弃用语法来创建一个helper函数,它可以分解成三个 部分: 首先,我们流星的模板通过关键词搜索模板工程。我们只 有一个模板,但是一个完整的项目会更多。 第二,通栏广告关键字指的是我们创建模板的名称 早些时候。每一个helper函数必须附加到一个模板。在这种情况下,附加功能 “排行榜”模板。 第三,球员关键字是我们给这个函数。我们很快就会参考 这个名字在HTML文件。 这个助手附加代码,将它与一个函数: Template.leaderboard。球员= function(){ / /代码在这里 } “助手”这个词可能会让这种声音的,但是我们没有做什么特别的。 我们已经创建了一个函数,将其命名为“球员”,并连接到“排行榜”模板。 添加一些功能函数,创建一个返回语句返回一些静态的 文本: Template.leaderboard。球员= function(){ 返回“其他文本” } 然后删除的文本“Hello World”模板,代之以“排行榜” 以下标记: 模板46 { {球员} } 在这里,我们使用的是另一个空格键标签,就是明证double-curly括号的使用。但 请注意,我们不使用大于符号,这是因为我们不包括 模板。相反,我们引用玩家函数的名称。 保存文件后,返回语句的文本应该出现在浏览器内: 使用弃用辅助函数方法。 如果文本不出现,一些是错误的代码,或者这种方法创建 从流星助手被移除。如果你不确定它,检查你的代码错误。 如果您的代码就是我告诉你写,它仍然不工作,不要害怕。现在, 你知道老方法创建辅助函数,我们准备讨论的新方法。 删除所有我们刚刚创建的helper函数,代之以: Template.leaderboard.helpers 在这里,我们有这个模板的关键字,搜索通过模板在我们的项目, 这个排行榜的关键字,这是一个引用“排行榜”模板。 但是这个帮手关键词呢? 我们创建一个函数命名的“帮手”? 不。 模板47 这个助手关键字是一个特殊的关键字,它允许我们定义多个辅助功能 在一个代码块。 因此,而不是创建一个helper函数: Template.leaderboard。球员= function(){ / /代码在这里 } 我们为所有的模板创建一个块的辅助功能: Template.leaderboard.helpers({ / /辅助函数到这里 }); 这些助手以JSON格式定义,与助手的名字和一个的关键 相关函数的值: Template.leaderboard.helpers({ “球员”:函数(){ 返回“其他文本” } }); 使用逗号分隔,我们可以创建多个辅助功能: Template.leaderboard.helpers({ “球员”:函数(){ 返回“其他文本” }, “otherHelperFunction”:函数(){ 返回“其他功能” } }); 可以使用这两个辅助函数在“排行榜”模板: { {球员} } { { otherHelperFunction } } 这段代码可能看起来有点忙比弃用的方法,但这只是因为我们 使用少量的帮手。更大数量的助手,组织他们 这是最清洁的方法。 模板48 一对辅助函数在一个模板。 模板49 每一块 我们已经取得了一个helper函数,但它只是返回一些静态文本,这并不是很有趣。 我们真正想要的是一个helper函数,从“PlayersList”中检索文档 收集。然后我们就可以从界面中显示数据。 为了达到这个目标,helper函数的返回语句替换为以下几点: 返回PlayersList.find() 在这里,我们使用find函数函数从“数据库,第1部分”一章。这个函数 将从“PlayersList”检索所有的数据集合,因为我们已经把它内 helper函数,这些数据现在可以从内部“排行榜”模板。 看到这,从HTML文件中删除以下标记: { {球员} } 之前,我们的helper函数返回之前的一段数据,字符串, 这个目的,这个标签是很好,但现在的助手是返回一个数组的所有文档 在集合,这意味着我们需要遍历返回的数据。 为了实现这一点,我们可以使用空格键语法来创建一个每个块: { { #每个玩家} } 测试 { { /每个} } 在这里,有几个事情: 首先,从“PlayersList”收集所有的文档检索的基础上,参考 玩家的功能。 第二,我们遍历返回的数据的每个语法。 第三,我们为每个文档输出“测试”这个词(球员)的检索。因为有 六名球员在收集、“测试”这个词会出现界面内的6倍。 模板50 “测试”这个词似乎每个玩家的收集。 从概念上讲,这就像我们有一个数组: var playersList =[“大卫”,“鲍勃”,“玛丽”,“比尔”,“沃伦”,“蒂姆”); …就像我们使用forEach循环遍历这个数组的值: var playersList =[“大卫”,“鲍勃”,“玛丽”,“比尔”,“沃伦”,“蒂姆”); playersList.forEach(函数(){ console.log(测试); }); 在每一块,我们也可以从内部文档检索字段的值。 因为我们把“PlayersList”收集的数据,我们可以显示的值 字段名字和分数。 显示玩家的名字,例如,我们可以写: { { #每个玩家} } { {名称} } { { /每个} } 然后显示玩家的分数,我们可以写: 模板51 { { #每个玩家} } { {名称} }:{ {得分} } { { /每个} } 虽然我们不会让这个应用程序很浪费时间,我们将添加一些细微的结构 的接口: < ul > { { #每个玩家} } <李> { {名称} }:{ {得分} } < /李> { { /每个} } < / ul > 保存文件后,玩家的名字和分数将会出现在一个无序列表。通过 默认情况下,球员们会按时间——从他们插入到集合 玩家添加第一个球员最近增加了更多,但这是我们改变 后一章。 一种改进的界面。 模板52 总结 在这一章,我们了解到: •流星为我们处理一些无聊的细节,如使用html标记和包括 JavaScript和CSS文件。 •通过创建模板,我们可以形成一个应用程序逻辑和我们之间的桥梁 接口。 •我们的项目的代码可以在客户端和服务器上运行,但我们并不总是想要的 这样的事情发生。我们可以使用isClient isServer条件控制的 代码运行。 •创建一个模板后,我们需要手动把它在界面。这给了 我们控制时间和地点。 •通过创建辅助函数,我们可以执行代码在一个模板,从而创建 一个动态的界面。 •如果一个helper函数返回一个数组的数据,我们可以通过数据在一个循环 模板使用每个语法。 流星的更深层次的理解: •意识到模板可以放置在任何地方项目的文件夹。我们可以, 实例,把我们的“排行榜”模板在另一个HTML文件和参考{ { > 排行榜} }将继续工作。 •故意打破应用程序通过将每个块之外的“排行榜” 模板。熟悉的错误,你会不可避免地遇到一颗流星 开发人员。然后你就会知道如何处理这些问题当他们意想不到的。 •创建一个helper函数,使用查找和计数函数返回的数量 球员“PlayersList”集合。然后在界面中显示这些数据。 在其当前状态查看代码,查看GitHub提交。 事件 在这一点上,我们有一个名单的球员出现在界面,但是没有办法 用户与该列表。数据动态地从“PlayersList”收集、检索 但用户仍将可能假定应用程序完全是静态的。 我们将花剩下的书解决这个问题,但在接下来的几个章节 特别的,我们将创建的影响能够选择球员名单内。 具体来说,当用户点击其中一个球员,球员的背景颜色 元素将会改变黄色。 53 事件54 创建一个事件 在本节中,我们将创建我们的第一个事件,事件使我们能够触发执行的代码 当用户点击一个按钮,轻拍一个关键键盘,或完成一系列其他 行动。 为了说明这一点,写在isClient条件如下: Template.leaderboard.events({ / /事件到这里 }); 在这里,有几个事情: 首先,模板是用来搜索所有的项目模板。 第二,排行榜是模板的名称我们要附加事件。 第三,事件是特殊的关键字,是用于指定,在未来的 代码,我们希望指定一个或多个事件。(这段代码非常类似于我们如何创建助手 功能。) 花括号之间的事件块,使用JSON格式创建一个事件: Template.leaderboard.events({ “点击”:函数(){ / /代码在这里 } }); 在这里,有两个事情: 首先,我们定义事件类型。这是点击部分。正因为如此,里面的代码 相关的函数将执行当用户点击的范围内的任何地方 “排行榜”模板。 第二,这个事件我们附加一个函数,这个函数里面,我们可以写 代码要执行时,单击出现。 为了说明这一点,添加一个控制台。日志语句内的事件: Template.leaderboard.events({ “点击”:函数(){ 控制台。日志(“你点击”); } }); 事件55 保存文件后,切换回Chrome和点击的范围内的任何地方 “排行榜”模板。每次点击,你点击“消息将出现在里面 控制台。 点击。 事件56 事件选择器 我们已经创建的事件是太过宽泛。它触发当用户单击任何地方范围内 “排行榜”的模板。在某些情况下可能是有用的,但通常我们 当用户希望触发一个事件做精确,喜欢点击某个按钮。 为了实现这一点,我们将使用事件选择器,选择符允许我们将事件附加到特定的HTML 元素。(如果你曾经使用jQuery,这个过程将是熟悉的,但如果不是这样,它仍然会相当 容易掌握。) 早些时候,我们把李HTML文件中的标签: <李> { {名称} }:{ {得分} } < /李> 目前的计划是让我们的事件触发李当用户点击其中一个元素。 要做到这一点,改变事件如下: “李点击”:函数(){ 控制台。日志(“你点击一个li元素”); } 在这里,我们做了两处修改: 首先,我们已经添加了李后点击关键字部分。这意味着事件将触发 当用户点击“排行榜”内任何li元素模板。 第二,我们已经改变了控制台的输出。日志语句。 然而,我们还没有考虑: 会发生什么,如果我们有其他的li元素内部的“排行榜”模板,不是吗 玩家的列表的一部分吗?以后会这样,我们的代码的目前的形式来看,它会引发一场 问题。事件将触发当我们不希望它来触发。 为了解决这个问题,添加一个。球员对li元素类: <李类= “玩家” > { {名称} }:{ {得分} } < /李> 然后使用这类事件选择器: 的点击。球员”:函数(){ 控制台。日志(“你点击。球员元素”); } 在这里,我们已经取得了如此事件只会触发,当用户单击一个元素 的。播放器类连接到它。 保存文件后,最后的结果不会出现任何不同,但是如果我们添加其他元素 模板,事件不会触发的时候不应该。 事件57 点击一个球员。 事件58 总结 在这一章,我们学到的: •当用户点击一个按钮,提交一个表单,或完成其他操作,我们可以 触发器的执行代码通过使用事件。 •最常见的事件类型是点击,但是有一个可用的其他选项范围 以许多不同的方式使我们的应用程序交互。 •通过使用事件选择器,我们可以精确的元素的附加事件 类似的语法jQuery和CSS。 流星的更深层次的理解: •尝试不同的事件类型,包括:双击鼠标,焦点,模糊,鼠标悬停, 改变。找出这些不同类型的行为,试图整合他们 排行榜的应用程序。 在其当前状态查看代码,查看GitHub提交。 会话 当用户点击其中一个。球员元素,执行一个函数。当这个函数是 触发,我们想改变背景颜色的元素,从而产生的效应 被选中的球员。 为了实现这一点,我们将使用会话,会话允许我们不存储小块的数据 保存到数据库并返回访问不会记得。这类数据可能 听起来不立即有用,但这是一个令人惊讶的是通用的方法来解决很多共同之处 问题。 59 会话60 创建一个会话 创建一个会话,写在单击下面的语句。球员事件: 会话。集(“selectedPlayer”、“会话值测试”); 这里,我们使用这个会话。设置功能,通过两个参数: 首先,我们通过会议的名称。这个名字被用作参考。在这个 情况下,我们调用会话“selectedPlayer”,但随意使用任何你喜欢的名字。 其次,我们通过会议的价值。这是我们内部存储的数据 会话。在这种情况下,我们通过“会话值测试”的静态值,但我们会 使用一个更有趣的值。 证明我们的会话是按预期工作,检索的会议的价值 下面的语句: Session.get(“selectedPlayer”); 块应该类似的事件: Template.leaderboard.events({ 的点击。球员”:函数(){ 会话。集(“selectedPlayer”、“会话值测试”); Session.get(“selectedPlayer”); } }); 这里,我们使用这个会话。函数,通过“选择——的名称 玩家“会话,我们刚才创建的。 输出该会话的值到控制台,它在一个变量: var selectedPlayer = Session.get(“selectedPlayer”); 然后添加一个控制台。日志声明下面这条线: var selectedPlayer = Session.get(“selectedPlayer”); console.log(selectedPlayer); 现在,当用户点击其中一个球员元素,“会话值测试”字符串 存储在一个会话,然后立即输出到控制台。它不是最有用的代码, 但这很快就会改变的。 61年会议 创建和检索一个会话。 62年会议 玩家的ID 当用户点击列表中的玩家之一,我们要抓住玩家的惟一ID 并将其存储在“selectedPlayer”会议。这将允许我们改变背景 这个玩家的li元素的颜色。 如果你不确定我是什么意思,当我说“玩家”的惟一的ID,回想 当我们球员插入“PlayersList”集合。每次我们使用插入 函数,一个随机的数字和字母会出现。混乱是唯一的ID 的球员。 首先,创建一个“playerId”变量的顶部点击。球员的事件,并使其平等 从之前的“会话值测试”字符串: var playerId =“会话值测试”; 然后修改会话。集函数,通过“playerId”变量作为第二个 论点。事件应该类似于: 的点击。球员”:函数(){ var playerId =“会话值测试”; 会话。集(selectedPlayer,playerId); var selectedPlayer = Session.get(“selectedPlayer”); } 在这一点上,关键是要使“playerId”变量等于球员的惟一ID 这是被点击。这并不需要大量的代码,但它确实需要一些解释。 现在,改变“playerId”变量如下: var playerId = this._id; 至于原因,有两个事情: 首先,我们有一个参考,这取决于上下文的价值。在这种背景下, 这个指的是文档的球员刚刚点击。 第二,_id部分是包含惟一的ID字段的名称的球员。所以在 我们创建了一个名字和分数一样,蒙戈为每个文档创建一个_id字段。 (下划线本身没有任何特殊的意义。这只是部分字段的名字。) 由于这一变化,现在下面是可能的: 1。用户点击的一个球员。 2。玩家的惟一ID存储在“playerId”变量。 3所示。“playerId”变量的值存储在“selectedPlayer”会话。(可以 只有一个值存储在一个会话,所以每当一个新值存储,前面的 值是重写。) 63年会议 4所示。“selectedPlayer”会话的值输出到控制台。 看到这在行动:保存文件,切换回Chrome,点击任何球员 列表。他们惟一的ID将显示在控制台。 点击大卫后,鲍勃和玛丽。 因为我们不需要看到控制台内的点击播放器的惟一的ID,我们可以 简化事件如下: 的点击。球员”:函数(){ var playerId = this._id; 会话。集(selectedPlayer,playerId); } 在这里,我们只是设置的值“selectedPlayer”会议,点击的惟一ID 的球员。 64年会议 选择效果,第1部分 当用户点击一个球员在我们的列表中,我们想要改变背景颜色 包含该玩家的li元素的属性。这将创建该玩家的影响 被选中。 为了实现这一点,打开项目的CSS文件并创建一个名为“选择”的类。这门课应该 background属性,在这个例子中,我们将通过“黄色”的价值: .selected { 背景颜色:黄色; } 然后切换到JavaScript文件并创建一个“selectedClass”助手: Template.leaderboard.helpers({ “球员”:函数(){ 返回PlayersList.find() }, “selectedClass”:函数(){ / /代码在这里 } }); (你会发现两个助手都是在相同的代码块,和我们讨论 以前,这是可能使用逗号)。 至于这个函数的内容,我们会让它返回“选择”这个词: “selectedClass”:函数(){ 返回“选择” } 注意:我们需要返回的文本等于在CSS文件类的名称,因为 我们命名为“类”选择“在CSS文件中,我们返回“选择”从内部文本 这个函数。 接下来,切换到HTML文件并将引用这个“selectedClass”功能里面 li元素的class属性: <李类= “球员{ { selectedClass } } “ > { {名称} }:{ {得分} } < /李> “选择”类将被应用到每一个。球员的元素,从而改变了背景 每个元素的颜色:黄色 65年会议 “选择”类是应用于li元素。 这不是我们想要的但这是一个重要的一步。 66年会议 选择效果,第2部分 在我们继续之前,我想要证明的东西。 在selectedClass helper函数返回语句注释掉: “selectedClass”:函数(){ / /返回“选择” } 然后编写以下: “selectedClass”:函数(){ / /返回“选择” 返回this._id } 在这里,我们使用这个。_id检索的惟一ID的球员。而是的ID 输出到控制台,它会出现在每个li元素的class属性。这是 不是我们想要的但重要的是要知道,因为selectedClass函数 被执行在每一块,它可以访问所有的数据迭代 (包括球员的惟一的ID、姓名和分数)。 这证明:保存文件,切换到Chrome,右键单击li元素之一,并选择 “检查元素”选项。你会注意到每个玩家现在出现在的惟一ID class属性: 67年会议 球员们在每个类的惟一的ID属性。 知道了这一点,我们要做几件事: 首先,我们将删除返回。_id声明,因为它只是用于演示目的。 第二,我们将取消返回语句,因为我们想要selectedClass函数 返回“选择”的静态文本。 第三,我们将创建一个“playerId”变量的函数,this._——的价值 id: “selectedClass”:函数(){ var playerId = this._id; 返回“选择” } 第四,我们将创建一个“selectedPlayer”为“selectedPlayer”会话变量: 68年会议 “selectedClass”:函数(){ var playerId = this._id; var selectedPlayer = Session.get(“selectedPlayer”); 返回“选择” } 第五,将返回语句在下列条件: “selectedClass”:函数(){ var playerId = this._id; var selectedPlayer = Session.get(“selectedPlayer”); 如果(playerId = = selectedPlayer){ 返回“选择” } } 逻辑后如果你有麻烦,这是怎么回事: 当用户点击一个列表中的玩家,玩家的惟一ID存储在里面 “selectedPlayer”会议。然后该会话的ID匹配的所有ID 球员们在列表中。因为玩家的ID将永远是独一无二的,只能有一个 单匹配,匹配时,静态文本的“选择”将返回的 selectedClass功能和放置在球员li元素的class属性。基于 在这类,玩家的li元素的背景颜色会变成黄色。(和 因为会话只能存储一个值,只有一个球员可以选择一次)。 点击后,鲍勃。 这是最复杂的例子在这本书中,但是你只需要掌握一种基本的会话 其余的章节。它并不重要,如果你不“获得”的一切。 69年会议 总结 在这一章,我们了解到: •会议是用来存储小块的数据没有保存到数据库或 记得在返回访问。 •创建一个会话,我们使用会话。集函数,而检索的价值 会话我们使用会话。得到的功能。 •辅助函数和事件在每一块获得的数据 遍历的块。 流星的更深层次的理解: •考虑我们如何使用“selectedPlayer”会议。我们还可以做些什么 选中的球员的惟一的ID吗? 在其当前状态查看代码,查看GitHub提交。 数据库,第2部分 还有很多其余页的这本书,但是我们已经完成了大部分 从最初的排行榜应用程序特性。 剩下的我们将在本章的工作包括: •增加选择球员的得分能力。 •排名球员的得分(从最高到最低)。 •显示选中的球员的名字在名单上。 我们也可以减量的得分选择球员,这并不是的一个特征 原始的应用程序,但足够简单的添加。 70年 第2部分数据库,71 给5分 在“排行榜”模板,我们将创建一个“给5分”按钮,当点击时,会 增加选择的球员的得分。 开始,将下面的按钮在“排行榜”模板: < input type = “ button “ class = “增量” value = “给5分”> 按钮应该以外的每一块,类属性的设置 “增量”。 按钮做一些,添加以下事件的事件块内 JavaScript文件: 的点击。增量”:函数(){ / /代码在这里 } 整个事件块应该类似于: Template.leaderboard.events({ 的点击。球员”:函数(){ var playerId = this._id; 会话。集(selectedPlayer,playerId); }, 的点击。增量”:函数(){ / /代码在这里 } }); (别忘了事件之间用逗号分隔)。 在点击。增加事件,我们将使用选定的玩家发现的惟一ID 玩家在“PlayersList”收集和增加球员的得分字段的值 5。 访问的唯一ID选择球员,使用会话。功能: 的点击。增量”:函数(){ var selectedPlayer = Session.get(“selectedPlayer”); } 您可以验证这个功能一个控制台。日志语句: 第2部分数据库,72 的点击。增量”:函数(){ var selectedPlayer = Session.get(“selectedPlayer”); console.log(selectedPlayer); } 选择一个球员之后,单击“给5分”按钮来显示所选的惟一ID 的球员。 单击“给5分”按钮后,玛丽的身份出现在控制台。 第2部分数据库,73 先进的运营商,第1部分 在这一点上,我们想做的是,当一个用户从列表中选择一个球员和点击 “给5分”按钮时,该玩家的分数是修改。 要做到这一点,删除控制台。从点击日志语句。增加事件和替换它 用以下: PlayersList.update(); 这是Mongo更新函数,在括号之间,我们可以定义: 1。什么文档(球员)我们要修改。 2。我们想修改文档。 要做到这一点,我们首先检索所选球员的文档。这可以通过通过 选中的球员的惟一ID: PlayersList.update(selectedPlayer); 这件事现在应该类似于: 的点击。增量”:函数(){ var selectedPlayer = Session.get(“selectedPlayer”); PlayersList.update(selectedPlayer); } 修改文档,我们通过第二个参数更新函数定义 文档的一部分,我们要改变: 的点击。增量”:函数(){ var selectedPlayer = Session.get(“selectedPlayer”); PlayersList。更新(selectedPlayer {得分:5 }); } 该语句将: 1。找到的文档选择的球员,根据玩家的ID。 2。更新文档通过改变比分字段的值为5。 第2部分数据库,74 但是如果你测试这个功能,你会发现它坏了。如果你选择了一个播放器,点击“给 5点”按钮,这名球员的名字将会消失。比分字段的值将会改变 5,按计划,但名称字段将完全从文档中删除。 玛丽去了哪里? 这可能看起来像是一个错误,但默认情况下,更新函数通过删除原来的工作 文档和创建一个新的文档与我们指定的数据。_id字段的值 将保持不变,但由于我们只指定update语句内的分数, 这是唯一的其他领域仍在修改文档。 考虑到这一点,我们需要使用一套Mongo运营商,让我们的价值得分 场没有删除原始文档。 首先,用以下代码替换更新函数的第二个参数: 的点击。增量”:函数(){ var selectedPlayer = Session.get(“selectedPlayer”); PlayersList。更新(selectedPlayer { $:}); } 这里,我们使用这个设置操作员修改一个字段的值美元(或多个字段) 删除原始文档。冒号后,我们只需要通过我们想要的字段 修改(和他们的新值): 第2部分数据库,75 的点击。增量”:函数(){ var selectedPlayer = Session.get(“selectedPlayer”); PlayersList。更新(selectedPlayer { $设置:{得分:5 } }); } 由于这一变化,更新函数不会被完全打破。如果我们保存文件 切换回Chrome,我们可以看到,选择一个球员和点击“给5分”按钮 将修改玩家的分数而不影响文档的其余部分。 设置分数而不破坏任何东西。 但尽管如此成功,我们仍然没有创建功能,我们旨在创建。因为 当我们的按钮可以设置选择玩家的分数5的价值,这就是它能做的。没有 多少次我们单击按钮时,字段的值不会增加任何进一步的。 修复这个问题,替换设置操作员与公司接线员:美元 的点击。增量”:函数(){ var selectedPlayer = Session.get(“selectedPlayer”); PlayersList。更新(selectedPlayer { $ . n:行情):{得分:5 } }); } 根据这一变化,每当更新函数触发,比分字段的值 将增加任何价值我们指定的值(在本例中,5)。 第2部分数据库,76 现在可以增加分数字段的值。 第2部分数据库,77 先进的运营商,第2部分 没有出现在原始的排行榜的功能应用程序是衰减的能力 分数。虽然这样的特性将会有用,因为它意味着我们可以: 1。惩罚玩家不遵守规则。 2。收回点错误地获得。 也是一个很简单的特性来扔在一起。 首先,创建一个“带5分”按钮在“排行榜”模板: < input type = “按钮”class =“减量”值=“带5分”> 与“给5分”按钮,把它在每个块和为它提供一个独特的 类属性(如“减量”)。 接下来,点击切换到JavaScript文件,复制。增加事件,将代码粘贴到 同样的事件。 块的事件应该类似于: Template.leaderboard.events({ 的点击。球员”:函数(){ var playerId = this._id; 会话。集(selectedPlayer,playerId); }, 的点击。增量”:函数(){ var selectedPlayer = Session.get(“selectedPlayer”); PlayersList。更新(selectedPlayer { $ . n:行情):{得分:5 } }); }, 的点击。增量”:函数(){ var selectedPlayer = Session.get(“selectedPlayer”); PlayersList。更新(selectedPlayer { $ . n:行情):{得分:5 } }); } }); 在这一点上,我们只需要做两个变化: 首先,更改为新创建的事件选择器。.decrement增量。 第二,价值5通过公司运营商,而不是值为5。附加的 ——逆转算子的功能,现在美元的公司操作符将衰减值 的分数。 最后一个事件的代码应该类似于: 第2部分数据库,78 的点击。减量”:函数(){ var selectedPlayer = Session.get(“selectedPlayer”); PlayersList。更新(selectedPlayer { $ . n:行情):{得分:5 } }); } 有点冗余的代码,我们有两个几乎相同的事件——但这是 我们在后面的章节会修理。 第2部分数据库,79 对文档进行排序 目前,球员名单中排名的时候他们插入 收集,而不是通过他们的分数排名。 为了解决这个问题,我们将修改里面的球员helper函数返回语句: “球员”:函数(){ 返回PlayersList.find() } 首先,通过一对大括号的括号找到功能: “球员”:函数(){ 返回PlayersList.find({ }) } 通过使用这些花括号,我们明确说明我们想要检索的所有数据 从“PlayersList”集合。这是默认的行为,所以这两个语句 技术上: 返回PlayersList.find() 返回PlayersList.find({ }) 但经过花括号作为第一个参数,我们可以通过第二个 参数,在这第二个参数,我们可以定义如何想对数据排序 检索。 作为第二个参数,通过接线员: PlayersList返回。找到({ },{ }): (不像集和美元公司经营者,我们不使用美元符号的这个操作符 的名字。) 然后选择排序的字段的值: PlayersList返回。找到({ },{:{分数:1 } }) 通过值传递,我们可以按照降序排列。这意味着我们的排序 从得分最高的球员得分最低。如果我们通过一个值的球员 将排序分数最高的分数最低。 第2部分数据库,80 基于他们的分数排名球员。 基于这种变化,球员们将会根据他们的分数排名,但是如果两个 玩家同样的分数吗? 采取“鲍勃”和“比尔”,例如。如果他们有相同的分数,比尔应该排名高于鲍勃 因为,按字母顺序,首先是他的名字。但此刻,不会发生因为鲍勃 比尔之前添加到集合。 为了解决这个问题,name字段通过运营商,但是这一次,通过的值 1而不是1: PlayersList返回。找到({ },{:{分数:1,名字:1 } }) 球员们仍将主要由他们的分数排名,但是一旦发生了排序, 球员们也会在他们的名字。这二次排序将发生在提升 (字母)。 第2部分数据库,81 基于分数和排名的名字。 根据这一变化,如果Bob和比尔有相同的分数,比尔会排名高于鲍勃。 第2部分数据库,82 个人文档 当用户选择其中的一个球员,球员的名字将出现在列表中 的球员。这并不是最有用的功能,但是: 1。这是最初的排行榜的一部分应用程序。 2。这意味着我们可以谈论一些流星的特性。 在JavaScript文件,创建一个helper函数,连着“showSelectedPlayer” “排行榜”模板: “showSelectedPlayer”:函数(){ / /代码在这里 } 内部函数,获取当前选中的球员的惟一ID: “showSelectedPlayer”:函数(){ var selectedPlayer = Session.get(“selectedPlayer”); } 然后写一个返回语句,返回数据从一个文档内 “PlayersList”集合。我们可以使用find函数,但findOne函数是首选 选择: “showSelectedPlayer”:函数(){ var selectedPlayer = Session.get(“selectedPlayer”); 返回PlayersList.findOne(selectedPlayer) } 通过使用findOne函数,我们可以通过文档作为唯一的惟一ID 参数,我们可以避免不必要的开销,因为这个函数只 尝试检索单个文档。它不会像找到浏览整个集合 将函数。 有了这个功能,切换到HTML文件并将引用里面的函数 “排行榜”模板。我把我的列表的底部,李两两之间的标签: <李>选中的球员:{ { showSelectedPlayer } } < /李> 但是如果我们保存文件,输出看起来不完全正确,因为findOne函数 是球员的整个文档检索。为了解决这个问题,我们需要指定,我们只希望 显示名称字段的值,可以用点符号: 第2部分数据库,83 <李>选中的球员:{ { showSelectedPlayer.name } } < /李> 现在的接口将类似于: 显示选中的球员的名字。 我们也应该让模板并不试图显示如果一个球员一个球员的名字 不是选择,可以用一个简单的条件: { { #如果showSelectedPlayer } } <李>选中的球员:{ { showSelectedPlayer.name } } < /李> { { /如果} } 这个列表项将只出现一个球员当前是否选中。 第2部分数据库,84 总结 在这一章,我们了解到: •在默认情况下,蒙戈更新功能的更新和删除文档 再现与指定的字段(同时保留相同的主键)。 •改变文档的值没有先删除它,设置操作员需要美元 被使用。这个操作符只会指定文档的值没有改变 影响文档的其余部分。 •公司美元操作符可以用来增加一个字段的值在一个特定的 文档。 •公司美元操作符可以用来衰减被放置的-一个字段的值 前面的符号指定的值。 •排序操作符可以用来排序的数据找到返回的函数。它 可以由多个字段排序。 •findOne函数只会从集合中检索单个文档, 更有效的方法,如果你只需要检索单个文档。 流星的了解: •让“给5分”按钮只出现在用户已经选择。这 是最初的排行榜的功能的应用程序。 •浏览“运营商”部分Mongo文档看看的 可以通过纯粹的数据库操作。 在其当前状态查看代码,查看GitHub提交。 形式 我们已经完成重建原始排行榜的应用程序,但有足够的空间 扩大同新功能的应用程序。在这个章节中,我们将创建一个表单 允许用户添加玩家排行榜,连同其他界面控件。 85年 86年形式 创建一个表单 在HTML文件,创建一个名为“addPlayerForm”的第二个模板: <模板名称= “ addPlayerForm “ > < /模板> 包括这个地方在“排行榜”模板: { { > addPlayerForm } } 在“addPlayerForm”模板,创建以下两个元素: 1。一个文本字段的名称属性设置为“playerName”。 2。提交按钮的值属性设置为“添加球员”。 模板应该类似于: <模板名称= “ addPlayerForm “ > <形式> < input type = “ text “ name = “ playerName “ > < input type = “ submit “ value = “添加球员” >
< /形式 < /模板> 由此产生的界面不会漂亮,但这是我们所需要的。 87年形式 一个表单添加球员排行榜。 88年形式 “提交”事件 我们已经见过几个点击事件的例子,我们可以触发执行 的代码,当用户单击一个特定的元素。同样,还有提交 事件,它允许触发执行的代码,当用户提交表单。 为此,创建另一个事件块isClient内部条件: Template.addPlayerForm.events({ / /事件到这里 }); (我们需要一个新的事件块,因为这一事件将被附加到新的“addPlayerForm” 模板,而不是“排行榜”模板。) 在这个事件块中,创建事件和事件类型设置为“提交”选择器集 “形式”: Template.addPlayerForm.events({ 的提交表单:函数(){ / /代码在这里 } }); 基于这段代码中,事件的函数时将触发“addPlayerForm”内的形式 模板提交。 但是我们为什么不只是使用的单击事件形式?不会大多数用户单击submit按钮 呢?可能是这样,但重要的是要记住,可以提交表单 多种方式。在某些情况下,用户单击submit按钮,但其他时候他们会 点击“返回”键在键盘。通过使用submit事件类型,我们可以考虑 为每一个可能的方式,可以提交表单。 确认事件是按预期工作,放置一个控制台。日志声明里面: 的提交表单:函数(){ 控制台。日志(“形式提交”); } 但事实证明,实际上是一个事件的问题,因为当我们提交表单: 1。web浏览器刷新页面。 2。提交的“形式”的信息不会出现在控制台。 89年形式 这为什么会发生? 当我们把一种形式在一个网页,浏览器假设我们想要的数据 ,并将其发送。问题是,当使用流星,我们不想 发送数据在任何地方——我们想要保持在当前页面——但这不是 标准行为浏览器而言,web页面刷新。 知道了这一点,我们必须禁用默认行为,web浏览器连接到表单。 这需要两个步骤。 90年形式 事件对象,第1部分 从一颗流星应用程序内触发事件时,我们可以访问的信息 该事件发生。这听起来可能很奇怪,但展示我的意思是,修改提交 表单事件如下: 提交表单:函数(事件){ 控制台。日志(“形式提交”); console.log(event.type); } 在这里,我们通过这个“事件”关键字通过事件的函数的括号,然后 输出事件的价值。输入到控制台。 这个结果是双重的: 首先,任何关键字通过事件的函数的括号作为第一个参数 变成了一个参考。因为我们通过“事件”关键字,我们 可以参考事件在事件的函数使用关键字。但是,您可以使用 您所喜欢的任何一个字。(一种常见的惯例是使用“evt”或“e”而不是“事件”)。 第二,事件。类型是指的“type”属性事件对象。作为一个结果, 这段代码应该输出控制台“提交”这个词,因为这是事件的类型 被触发。 这并不能解决原来的问题尽管由于我们的页面刷新时表单 提交,我们不能看到控制台。日志语句。 为了解决这个问题,使用preventDefault函数: 提交表单:函数(事件){ event.preventDefault(); 控制台。日志(“形式提交”); console.log(event.type); } 当附加到事件对象,这个preventDefault函数阻止默认行为 事件的发生。因为我们已经附加函数提交表单事件: 1。默认情况下,提交表单不会做任何事情。 2。我们需要手动定义表单的功能。 3所示。控制台。日志语句现在将正常工作。 保存文件,切换回Chrome和测试表单,它不再是刷新 页面。 91年形式 控制的形式。 注意:preventDefault函数不仅适用于形式。例如,你可以 完全控制的链接在一个模板: “点击”:函数(事件){ event.preventDefault(); } 有了这个代码,模板中的任何一个元素不会像他们通常 会。你必须手动分配功能。 92年形式 事件对象,第2部分 现在我们已经完全控制的形式,我们希望提交表单的事件的 “playerName”文本框的内容提交表单时,和使用价值 添加一个球员到数据库。 首先,创建一个名为“playerNameVar”的变量: 提交表单:函数(事件){ event.preventDefault(); var playerNameVar; } 然后让这个变量等于“event.target。playerName”和输出变量的值 控制台: 提交表单:函数(事件){ event.preventDefault(); var playerNameVar = event.target.playerName; console.log(playerNameVar); } 这语句使用事件对象获取任何HTML元素的name属性 设置为“playerName”。 但这段代码不工作正如你所想的那样,因为控制台。日志语句输出 的原始HTML文本字段,而不是它的价值: 抓住整个文本字段。 这是因为我们需要显式地检索价值属性: 93年形式 提交表单:函数(事件){ event.preventDefault(); var playerNameVar = event.target.playerName.value; console.log(playerNameVar); } 基于这种变化,无论用户输入文本字段将“playerName” 提交表单时输出到控制台。 文本字段的值出现在控制台。 提交的播放器插入“PlayersList”收藏,添加里面的插入功能 提交表单的事件: PlayersList.insert({ 名称:playerNameVar, 得分:0 }); 而不是通过一个硬编码值名称字段,如“大卫”或“Bob”,通过 通过“playerNameVar”变量的引用。 现在事件的代码应该类似于: 94年形式 提交表单:函数(事件){ event.preventDefault(); var playerNameVar = event.target.playerName.value; PlayersList.insert({ 名称:playerNameVar, 得分:0 }); } 和现在应该像预期的那样工作。 凯尔被添加到排行榜。 95年形式 删除玩家 自从我们成为可能添加球员排行榜,这是一个好主意让它成为可能 也从排行榜中删除玩家。 为了实现这一点,首先创建一个“删除玩家”按钮在“排行榜”模板: < input type = “ button “ class = “删除” value = “删除玩家” > 与其他按钮在这个项目中,附加一个独特的类属性,我们可以参考 按钮的事件。 在JavaScript文件,将下列事件附加到“排行榜”模板: 的点击。删除”:函数(){ / /代码在这里 } 检索的ID选择球员的“selectedPlayer”会话: 的点击。删除”:函数(){ var selectedPlayer = Session.get(“selectedPlayer”); } 然后使用从集合中删除功能,删除选中的球员: 的点击。删除”:函数(){ var selectedPlayer = Session.get(“selectedPlayer”); PlayersList.remove(selectedPlayer); } 我们还没有谈到了去除函数,但没什么多说的。所有 我们要做的就是通过文档的惟一的ID作为唯一的参数。该文档 将从集合中删除。 用户将可以从列表中删除的球员。 96年形式 总结 在这一章,我们了解到: •通过使用submit事件类型,我们可以触发时执行代码是一种形式 提交。 •使用提交事件而不是单击事件以来可以提交的一种形式 许多不同的方式(如“返回”键。)。 •我们可以从内部访问信息的一个事件,事件的功能,和也 操纵事件发生。 •浏览器的默认行为附加到形式,干扰我们的代码,但这一点 行为与preventDefault函数可以禁用。 •当表单字段名称属性,有一个简单的语法的价值 表单字段。 •通过Mongo文档的ID通过删除功能,我们可以删除 特定的文档集合。 流星的更深层次的理解: •所以,后提交“添加球员”的形式,“playerName”文本的价值 字段是重置为空值。 •创建一个警告,要求用户确认他们是否真的想要删除一个 球员后从列表中点击“删除的球员”按钮。 •“分数”字段添加到“添加球员”形式,允许用户定义一个球员的得分 当他们被提交到列表中。 在其当前状态查看代码,查看GitHub提交。
账户 我们的应用程序有许多有用的特性,但仍只支持单个球员的名单。 这意味着只能有一个用户应用程序在任何特定的时间,也就是 愚蠢的网络应用程序。 为了解决这个问题,我们将创建一个用户帐户系统,这样是最简单的一个 我们可以做的事情与框架。 有了这个系统,我们将使它如此: •用户可以注册并登录到应用程序。 •注销用户不会看到“添加球员”的形式。 •每个用户将有自己的独特的排行榜。 它的很多功能,但不会花很多的代码。 97年 账户98 登录供应商 扩展我们的流星的功能项目在几秒钟之内,我们可以安装一个范围 包,包基本上是插件: 1。重要的功能添加到一个项目。 2。减少我们需要编写的代码量。 默认情况下,每个流星项目本地访问官方包的数量。这些都是 包,大多数开发人员需要使用在某种程度上,但不一定 在每一个项目。(也有成千上万的第三方包,但是他们超出了 这本书的范围,所以我们将只关注官方包。) 添加一个用户帐户系统我们的项目,我们将首先安装一个“登录供应商”包。这些 包使它非常容易为一个账户系统添加一个后端应用程序。 例如,通常创建一个用户帐户系统将涉及创建一个收集的 用户的数据: useraccount = new Mongo.Collection(“用户”); 然后编写应用程序逻辑注册和登录,等等。 但在处理流星时,所有我们要做的是切换到命令行并运行 下面的命令: 流星添加accounts-password 这里,我们将这个“accounts-password”包添加到项目中。这个包创建 后端账户系统依赖于电子邮件和密码注册和日志记录 在。 账户99 accounts-password包添加到项目中。 具体地说,这个包: 1。创建了一个集合存储注册用户的数据。 2。为我们提供了一系列有用的功能我们很快就会讨论。 其他登录供应商包可用,允许用户登录到我们的应用程序 通过服务像谷歌和Facebook,但因为这增加了一个额外的步骤流程, 我们专注于电子邮件和密码系统。 账户100 Meteor.users 一旦“accounts-password”包添加到项目中,自动集合 用来存储数据的注册用户。这个集合被称为流星。用户和它 工作就像我们可以创建自己的任何集合。 为了说明这一点,下面的命令输入到控制台: Meteor.users 返回的信息证实,这只是一个普通的集合: 检查出流星。用户收藏。 知道了这一点,我们可以使用查找和获取功能集合: .fetch Meteor.users.find()(); 但由于没有注册用户,将返回任何数据。 账户101 登录界面 我们已经设置账户的后端系统,但是前端呢?是 我们将编写接口代码,允许人们注册和登录和改变他们 帐户详细信息吗? 不。 我们可以创建一个定制的界面,它实际上是一个非常简单的事情,但有一个更容易 办法尽快启动并运行。 即时向项目添加账户系统的前端,我们只是必须安装 “accounts-ui”包: 流星添加accounts-ui 然后,一旦安装,以下正文标签之间的HTML文件(或在一个 的模板): { { > loginButtons } } 这里,我们包括这种“loginButtons”模板,这是包含在“accounts-ui” 包中。因为这个包被添加到这个项目中,我们现在可以包括这个模板 任何我们想要的接口。 看看这个模板包含,保存文件并切换到浏览器。你会注意到一个”的迹象 出现在“按钮,当点击,一个登录表单和一个“创建帐户”链接将出现: 账户102 一个即时的接口。 虽然这不是一个纯粹的虚拟接口。已经没有任何配置,这是有可能的 用户注册、登录和注销。没有理由做这些事情——注册 和非注册用户将看到相同的内容,但这是我们将在未来解决 部分。 现在,使用查找和获取函数的流星。用户组: 账户103 第一个用户的数据。 返回你会注意到一个文档,该文档包含的数据 这是刚刚创建的。您可以单击箭头看到面临的下行数据联系在一起 该帐户。 账户104 登录状态 目前,未注册用户可以看到“添加球员”形式,不赚很多 有意义的。这种形式注册用户只能访问。 为了达到这个目标,改变“addPlayerForm”模板如下: <模板名称= “ addPlayerForm “ > { { #如果currentUser } } <形式> < input type = “ text “ name = “ playerName “ > < input type = “ submit “ value = “添加球员” >
< /形式 { { /如果} } < /模板> 在这里,我们指的是这个currentUser对象检查当前用户是否已登录。 这个对象所提供的“accounts-password”包,和逻辑很简单: 1。如果当前用户登录,currentUser将返回true。 2。如果当前用户没有登录,currentUser将返回false。 因此,只有几行代码,我们使它所以只有登录用户可以 (相互作用)的形式。 账户105 为每个用户分配一个排行榜 使我们的应用程序有些有用的更广泛的受众,我们需要让每一个 注册用户可以自己独立的球员名单。它可能不明显 我们怎么做这个,最困难的一点编程弄清楚吗 如何处理这样的问题,但这个过程本身不涉及很多步骤。 首先,下面的语句: var currentUserId = Meteor.userId(); 提交表单事件:内… 提交表单:函数(事件){ event.preventDefault(); var playerNameVar = event.target.playerName.value; var currentUserId = Meteor.userId(); PlayersList.insert({ 名称:playerNameVar, 得分:0 }); } 在这里,我们创建这个“currentUserId”变量,存储返回的值的 流星。标识功能。我们还没有谈到这个函数,但并不多 解释一下。它只是返回当前登录用户的惟一ID。 然后添加一个“createdBy”字段中插入功能,并通过“currentUserId” 变量: PlayersList.insert({ 名称:playerNameVar, 得分:0, createdBy:currentUserId }); 因此,当用户添加一个球员排行榜,该用户的惟一ID 与玩家相关的补充道。 为了演示这个: 1。保存文件。 2。切换回Chrome。 3所示。添加一个球员排行榜。 账户106 然后使用“PlayersList”上的发现和获取函数集合,并单击downwardfacing 箭头为最近创建的文档。您将看到如何该文档包含了 用户的ID此玩家添加到集合中。 将一个球员与一个用户相关联。 接下来,我们将修改玩家helper函数: “球员”:函数(){ PlayersList返回。找到({ },{:{分数:1,名字:1 } }); } 首先,设置另一个“currentUserId”变量: “球员”:函数(){ var currentUserId = Meteor.userId(); PlayersList返回。找到({ },{:{分数:1,名字:1 } }); } 然后改变返回语句,所以只返回球员当他们createdBy字段是相等的 当前登录用户的惟一ID: 账户107 “球员”:函数(){ var currentUserId = Meteor.userId(); PlayersList返回。找到({ createdBy:currentUserId }, {:{分数:1,名字:1 } }); } 这可以确保用户只能看到球员他们添加到排行榜中,从而产生的效应 ,每个用户都有自己的独特的球员名单。 只看到球员属于当前用户。 账户108 项目重置 目前,有一些球员在数据库没有连接到任何特定的人 用户——球员被添加到前一节中——这意味着我们之前数据库 不需要他们在我们集合。 给自己一个全新的开始,然后,切换到命令行,停止与CTRL本地服务器
- C,输入以下命令: 流星重置 这将勾销数据库,因为我们写的代码在前一节中, 此时玩家添加到集合将被附加到当前登录的用户。 你可能会发现自己使用这个命令半定期,大量无用的数据很容易 在开发过程中填充数据库。 账户109 总结 在这一章,我们了解到: •包让我们迅速向应用程序添加功能。有一些官员 包,还有成千上万的第三方包。 •“登录供应商”包来创建一个账户的后端系统。我们可以 创建一个后端,依赖于电子邮件和密码,或者像Twitter和服务 Facebook(或服务)的组合。 •安装登录提供者包之后,一颗流星。用户自动收集 用来存储数据的注册用户。 •accounts-ui包允许我们快速添加一个账户系统的用户界面 一个项目。你可以把一个自定义的方法,但这个样板的方法是伟大的 对于初学者来说。 •我们可以检查当前用户是否已登录通过引用curentUser 对象从一个模板。 •的惟一的ID来检索当前登录的用户,我们可以使用Meteor.userId() 函数。 流星的更深层次的理解: •安装一个不同的登录供应商包装,像accounts-twitter包(但 确定accounts-ui包也是安装)。 •浏览atmospherejs.com查看很多第三方包 流星。 在其当前状态查看代码,查看GitHub提交。 发布与订阅 到目前为止,我们已经构建了一个功能丰富的应用程序与流星,但我们没有说什么 安全,这是一个很大的网络软件开发的一部分。在大多数情况下,我想要的 向你们展示如何构建尽可能快速和简单的东西,但也有几个 安全我们应该谈论的话题前发布到web项目。 首先,让我们来谈谈出版物和订阅。 110年 发布和订阅111 数据安全 展示我们的项目的一个安全缺陷: 1。注册两个单独的用户帐户。 2。每个帐户下,添加三个球员。 3所示。注销的账户。 正因为如此,共有6名球员应该存在在数据库和他们应该“属于” 总共有两个用户。 下一步,使用“PlayersList”上的发现和获取功能集合: .fetch PlayersList.find()(); 你会注意到,我们以前见过,所有返回的数据收集。我们可以 看到所有的数据属于两个用户。但这实际上是一个问题。因为除非 我们关闭这个功能,这个应用程序的每个用户将有同样的,肆无忌惮的访问权 每一个数据库内的数据。没有什么阻止他们深入挖掘 “PlayersList”收集的发现和获取功能。 访问所有的数据。 这个项目的数据不是特别敏感,它不像我们存储信用卡号码 ——但: 发布和订阅112 1。如果我们存储敏感数据,这将是一个不可原谅的监督。 2。它有害的实践数据提供给用户当它不是必需的。 然而,这并乞求问题: 为什么这个功能存在的流星?如果是这样一个巨大的安全风险来访问数据 通过控制台,为什么允许这样做吗? 很简单,方便。在本书中,我们已经使用查找和获取 函数和他们伟大的工具来管理和操作的内容 数据库。只是,在我们与世界分享应用程序之前,我们必须: 1。禁用这种默认行为,限制访问的大部分数据。 2。精确地定义数据应该提供给特定的用户。 这就是我们将讨论接下来的章节。 发布和订阅113 autopublish 功能,允许我们使用控制台导航项目的数据 包含在一个“autopublish”包包含在默认情况下每个流星项目。 如果我们删除这个包,用户无法通过控制台访问任何数据,但它 也将打破应用程序,因此我们需要采取一些额外的步骤。 删除“autopublish”包从项目,运行以下命令: 流星删除autopublish 如果你登录的用户帐户删除包的时候,你不会注意到 任何不同,但尝试发现和获取功能: .fetch PlayersList.find()(); 你会注意到我们再也不能浏览里面的数据集合。唯一的 返回一个空数组。它看起来像数据已被删除,但事实并非如此。 它只是被获得。 现在问题是,我们的数据安全,因为如果我们登录的用户帐户, 数据也无法访问的接口: 没有可用的数据。 为了解决这个问题,我们需要找到一些我们面临的两个极端——之间的中间立场 一切都被访问和没有被访问。这涉及到精确的定义 数据应该提供给我们的用户。 发布和订阅114 isServer 在本书中,我们主要是在isClient条件编写代码。这是 因为我们大多写的代码意味着浏览器内运行(如代码 影响界面)。然而,很多情况下我们希望代码运行 在服务器上。 为了演示这些情况之一,地方在isServer如下声明 在JavaScript文件的条件: .fetch console.log(PlayersList.find()()); 不出所料,输出出现在命令行(而不是控制台),但要注意 我们没有任何麻烦检索“PlayersList”收集的数据。即使在 删除“autopublish”计划,我们有自由统治的数据直接在工作 与服务器。 为什么? 嗯,在服务器上执行的代码本身是可信的。所以,当我们停止用户 应用程序访问数据的前端——在客户端——我们可以继续 在服务器上检索数据。 你很快就会知道这个细节的有效性。 发布和订阅115 出版物,第1部分 在本节中,我们将发布“PlayersList”内的数据收集,和 从概念上讲,你能想到的出版数据传输数据到从服务器 醚。我们只是指定哪些数据应该提供给用户。我们不关心的地方 最终的数据。 为了实现这一点,删除控制台。日志声明isServer条件和替换它 一颗流星。发布功能: Meteor.publish(); 这个函数的括号之间,通过“应”作为第一个参数: Meteor.publish(球员); 这个论点是一个名字,我们会参考。 然后,作为第二个参数,通过一个函数: 流星。发布(“球员”,函数(){ / /内部发布功能 }); 在这个函数,我们指定哪些数据应该提供给应用程序的用户。 在这种情况下,我们将返回所有的“PlayersList”收集的数据: 流星。发布(“球员”,函数(){ 返回PlayersList.find() }); 这段代码复制autopublish的功能,这意味着它不是我们什么 想要的,但这是一个正确方向的一步。 发布和订阅116 订阅 因为流星。发布在服务器上执行的函数,我们现在可以订阅 这些数据在isClient条件,再一次做项目的数据访问 通过浏览器和控制台。 如果你想象一下,发布功能是传输数据到醚,然后订阅 函数是我们使用“捕捉”数据。 在isClient条件,写如下: Meteor.subscribe(); 这是流星。订阅功能,唯一的参数,我们需要通过 发布函数的名称: Meteor.subscribe(球员); 保存文件,然后使用“PlayersList”上的发现和获取功能集合: .fetch PlayersList.find()(); 你会注意到,再一次,我们可以访问所有的数据从项目的数据库, 意味着我们的应用程序是回到原来的状态。这还不是我们想要的,但这是另一个 重要的一步。 发布的所有数据。 发布和订阅117 出版物,第2部分 现在的目标是让流星。发布函数只从服务器发布数据 属于当前登录的用户。 这意味着: 1。登录用户只能访问自己的数据。 2。注销用户没有访问任何数据。 最后,应用程序将全功能保护潜在的敏感 数据。 为了达到这个目标,我们需要访问当前登录用户的惟一ID从内 流星。发布功能。在这个函数,我们不能使用Meteor.userId() 之前的功能。相反,我们必须使用下面的语句: this.userId; 虽然语法是不同的,最终的结果是一样的。该语句返回唯一的 当前登录用户的ID。 声明在“currentUserId”变量: 流星。发布(“球员”,函数(){ var currentUserId = this.userId; 返回PlayersList.find() }); 然后改变找到函数只所以检索文档createdBy字段是相等的 当前登录用户的ID: 流星。发布(“球员”,函数(){ var currentUserId = this.userId; PlayersList返回。找到({ createdBy:currentUserId }) }); 保存文件,然后使用“PlayersList”上的发现和获取功能集合: .fetch PlayersList.find()(); 如果你登录,您只会看到的数据属于当前用户的帐户,如果 你没有登录,你不会看到任何数据。这是因为内部的返回语句 流星。发布函数只能返回文档,包含当前的惟一ID 用户。 发布和订阅118 返回一个有限选择的数据。 也知道,我们现在可以简化玩家从这个函数: “球员”:函数(){ var currentUserId = Meteor.userId(); PlayersList返回。找到({ createdBy:currentUserId }, {:{分数:1,名字:1 } }); } …: “球员”:函数(){ var currentUserId = Meteor.userId(); PlayersList返回。找到({ },{:{分数:1,名字:1 } }); } 为什么? 因为球员内部的返回语句函数只能检索数据 从服务器发布。因此,指定要检索用户的数据 两个地方是多余的。我们只需要定义Meteor.publish中返回的数据 函数。 发布和订阅119 总结 在这一章,我们了解到: •在默认情况下,所有的数据在一个流星项目的数据库提供给所有用户 应用程序。这是方便的在开发期间,但它也是一个很大的安全漏洞 需要在部署前固定。 •这个默认功能都包含在一个“autopublish”包。如果我们删除这个 计划,项目将更安全,但它也会打破,需要固定的。 •流星。发布函数定义哪些数据应该在服务器端 提供给应用程序的用户。 •流星。订阅功能是用于客户端检索的数据 从服务器发布。 •在发布功能,我们不能使用Meteor.userId()函数,但我们可以 与this.userId检索当前用户的ID。 在其当前状态查看代码,查看GitHub提交。 方法 在前面的章节中,我们讨论的第一个包含两个主要的安全问题 每颗流星项目默认情况下。这个问题是用户通过导航的能力 所有的数据在数据库内部,直到我们把“autopublish”包。基于这些 我们做了改变,用户现在只有访问“属于”的数据。 为了演示第二个主要安全问题,输入以下命令控制台: PlayersList。插入({ name:“伪玩家”,分数:1000 }); 看有什么问题吗? 虽然我们已经取得了它所以用户不能浏览所有的数据在数据库中,用户 仍然能够自由使用控制台插入数据到数据库中。这意味着用户可以: 1。利用应用程序自己的优势。 2。数据库填充无用的、多余的数据。 用户还能够从数据库修改和删除数据,意味着在默认情况下, 他们主要有完全的管理权限。 与前面的安全问题,这个特性是当我们开发一个方便 应用程序,因为它很容易创建和管理数据,但这是一个我们需要的特性 关闭之前部署。 此功能包含在一个“没有安全感”包,我们可以删除它 项目使用下面的命令: 流星消除不安全的 删除包后,切换回Chrome和尝试和应用程序。 你会注意到: •我们再也不能给分的球员。 •我们再也不能拿分的球员。 •我们再也不能从列表中移除玩家。 •我们再也不能将玩家添加到列表。 所有的插入、更新和删除功能停止工作——都通过 接口和控制台应用程序,所以更安全的结果,但是我们会有 解决很多事情。 120年 方法对121 创建一个方法 直到这个时候,所有的插入、更新和删除功能已经在isClient 有条件的。这是快速和容易的方法,但这也是为什么我们的应用程序 天生没有安全感。我们已经把这些敏感,clientside数据库驱动的功能。 更安全的做法是将这些函数isServer条件,也就是说: 1。数据库代码将执行服务器的可信的环境中。 2。用户无法使用这些函数从控制台,因为用户没有 直接访问服务器。 为了实现这一点,我们将创建我们的第一个方法,方法执行的代码块 在服务器上被触发后从客户端。如果这听起来奇怪,不要害怕。这是 其中的一次,之后在写出代码将帮助解释很多。 在isServer条件,写如下: Meteor.methods({ / /方法去这里 }); 这是我们将使用代码块来创建我们的方法。你会发现语法很相似 我们如何创建两个助手和事件。 为了演示什么方法,创建一个“sendLogMessage”的方法: Meteor.methods({ “sendLogMessage” }); 然后将该方法与功能: Meteor.methods({ “sendLogMessage”:函数(){ 控制台。日志(“Hello world”); } }); 接下来,“电话”这个方法从底部的提交表单事件附加到“addPlayer - 形成“模板: 方法对122 提交表单:函数(事件){ event.preventDefault(); var playerNameVar = event.playerName.value; var currentUserId = Meteor.userId(); PlayersList.insert({ 名称:playerNameVar, 得分:0, createdBy:currentUserId }); Meteor.call(“sendLogMessage”); } 通过使用这颗流星。调用语句,通过我们创建的方法的名称, 我们能够触发方法时的执行“添加球员”提交表单。 保存文件,切换回Chrome,并提交“添加球员”形式。核心功能 这种形式的仍然是破碎的,但是如果你切换到命令行,您将看到“Hello 世界”的消息似乎每次提交表单。客户端表单的提交 触发的方法,但实际代码的方法是在服务器上执行。 代码在服务器上执行,导致当我们提交表单。 这个基本原则是我们在本章的其余部分使用。 方法对123 插入数据(再一次) 再次让应用程序工作,我们首先将插入函数里面提交 表单事件从客户机和服务器。 这意味着: 1。插入函数将成功地和安全地运行在服务器上。 2。用户仍然无法通过控制台插入数据。 换句话说,“添加球员”提交表单时,插入函数将触发 服务器从客户端触发后。 首先,“sendLogMessage”方法的名称更改为“insertPlayerData”,和摆脱 控制台。日志语句: Meteor.methods({ “insertPlayerData”:函数(){ / /代码在这里 } }); 在方法内部,抓住当前登录用户的惟一ID: Meteor.methods({ “insertPlayerData”:函数(){ var currentUserId = Meteor.userId(); } }); 然后下面添加一个熟悉的插入函数声明: Meteor.methods({ “insertPlayerData”:函数(){ var currentUserId = Meteor.userId(); PlayersList.insert({ 名称:“大卫”, 得分:0, createdBy:currentUserId }); } }); 这里,我们通过一个硬编码值的“大卫”,这并不是我们所想要的, 但这已经足够好了。 返回到提交表单事件和删除currentUserId变量和插入 函数。事件应该类似于: 方法对124 提交表单:函数(事件){ event.preventDefault(); var playerNameVar = event.target.playerName.value; Meteor.call(“sendLogMessage”); } 但也一定要通过正确的方法名流星。调用语句: 提交表单:函数(事件){ event.preventDefault(); var playerNameVar = event.target.playerName.value; Meteor.call(“insertPlayerData”); } 基于这些变化,“添加球员”形式将现在的工作。如果我们提交表单, 一个球员将被添加到“PlayersList”集合。我们只能添加球员叫“大卫”, 但在下一节我们将解决这个问题。 再次插入函数的工作。 现在,重要的是,用户可以添加玩家通过列表形式, 他们不能够使用插入函数从控制台。这意味着我们获得 控制用户如何与数据库的交互,这是一个保持应用程序的重要组成部分 安全。 方法对125 传递参数 “添加球员”形式的问题是文本字段的值没有被传递到 该方法。这样,当我们提交表单时,创建的球员的名字将永远 被设置为“大卫”。 为了解决这个问题,通过“playerNameVar”变量通过流星。调用语句作为第二 论点: 提交表单:函数(事件){ event.preventDefault(); var playerNameVar = event.target.playerName.value; 流星。调用(insertPlayerData,playerNameVar); } 然后允许接受这个论点的方法通过将“playerNameVar”之间 括号的方法的功能: Meteor.methods({ “insertPlayerData”:函数(playerNameVar){ var currentUserId = Meteor.userId(); PlayersList.insert({ 名称:“大卫”, 得分:0, createdBy:currentUserId }); } }); 正因为如此,我们现在可以参考“playerNameVar”参考用户的价值 进入表单的文本字段: Meteor.methods({ “insertPlayerData”:函数(playerNameVar){ var currentUserId = Meteor.userId(); PlayersList.insert({ 名称:playerNameVar, 得分:0, createdBy:currentUserId }); } }); 最后,这是发生了什么: 方法对126 首先,当提交表单时,“insertPlayerData”方法被调用时,和的值 表单的文本字段附加到电话。 第二,执行“insertPlayerData”方法。该方法接受的价值 “playerNameVar”变量,然后从里面引用变量方法的功能。 第三,插入函数内执行方法,因为这段代码运行在服务器上, 它可以运行没有“安全感”包。与刚才不同,这个函数使用价值 来自表单的文本字段,而不是硬编码的“大卫”的价值。 创建的球员与原名称。 表单将再次工作的预期,但仍然会是没有为用户操作方法 数据通过控制台。 方法对127 删除玩家(再一次) 以同样的方式,我们创建了一个“insertPlayerData”变量,我们要创建一个“removePlayerData” 方法,我们将连接到“删除的球员”按钮,里面是我们的接口。 就像我们如何创建助手和事件,我们的位置在一个代码块的方法, 记住要用逗号分开的方法: Meteor.methods({ “insertPlayerData”:函数(playerNameVar){ var currentUserId = Meteor.userId(); PlayersList.insert({ 名称:playerNameVar, 得分:0, createdBy:currentUserId }); }, “removePlayerData”:函数(){ / /代码在这里 } }); 然后我们会点击两个变化。删除事件: 首先,去掉删除功能: 的点击。删除”:函数(){ var selectedPlayer = Session.get(“selectedPlayer”); } 在它的位置,创建另一个流星。调用语句: 的点击。删除”:函数(){ var selectedPlayer = Session.get(“selectedPlayer”); Meteor.call(“removePlayerData”); } 通过“selectedPlayer”变量,第二个参数: 的点击。删除”:函数(){ var selectedPlayer = Session.get(“selectedPlayer”); 流星。调用(removePlayerData,selectedPlayer); } 允许接受这个论点的方法: 方法对128 “removePlayerData”:函数(selectedPlayer){ / /代码在这里 } 然后重新创建删除方法内部的函数: “removePlayerData”:函数(selectedPlayer){ PlayersList.remove(selectedPlayer); } “删除玩家”按钮将按预期工作,但用户仍然没有完成 管理访问数据库相关函数在控制台。 清除旧数据。 然而,一个挥之不去的问题… 因为“removePlayerData”方法执行从客户端,用户可以执行 同样的自称,从控制台: 流星。调用(‘ removePlayerData ‘,’ 8 sad8a90d8s9ad ‘); 因此,尽管他们没有获得全方位的插入、更新和删除功能 能做的,他们仍然可以做一些伤害。例如,他们可以运行这个命令来删除一个 玩家从另一个用户的列表。 这不是一个悲剧的巨大的安全漏洞,但这是我们应该解决的 准备在未来安全漏洞。 最好的做法是改变“removePlayerData”从这个方法: 方法对129 “removePlayerData”:函数(selectedPlayer){ PlayersList.remove(selectedPlayer); } …: “removePlayerData”:函数(selectedPlayer){ var currentUserId = Meteor.userId(); PlayersList。remove({ _id:selectedPlayer createdBy:currentUserId }); } 有了这段代码,该方法将只允许玩家从列表中被删除 球员属于当前用户。 注意:你可能会认为它不太可能用户会让这样一个混乱与另一个 用户的排行榜,但当涉及到安全,最好不要低估人民的能力 和渴望肆虐。 方法对130 修改分数 在这一章,我们已经使用方法为了安全,但我们也可以使用 方法来减少我们的项目代码的数量。 为了说明这一点,我们要结合点击。增加并单击。衰减事件 成一个单一的方法。这是有可能的,因为有很多的这些事件之间共享代码: 的点击。增量”:函数(){ var selectedPlayer = Session.get(“selectedPlayer”); PlayersList。更新(selectedPlayer { $ . n:行情):{得分:5 } }); }, 的点击。减量”:函数(){ var selectedPlayer = Session.get(“selectedPlayer”); PlayersList。更新(selectedPlayer { $ . n:行情):{得分:5 } }); } 事实上,唯一的区别是在点击。增加事件,我们传递一个值 通过公司操作符“5”,而在点击。衰减事件,我们通过 一个“5”的价值。 改善这段代码中,我们首先关注点击。增量的事件。 在事件中,删除更新函数,代之以一个流星。调用语句: 的点击。增量”:函数(){ var selectedPlayer = Session.get(“selectedPlayer”); 流星。调用(modifyPlayerScore,selectedPlayer); } 这里,我们称之为“modifyPlayerScore”的方法,这是一个我们将创建方法 时刻,我们通过“selectedPlayer”变量。 创建内部的“modifyPlayerScore”方法方法: “modifyPlayerScore”:函数(){ / /代码在这里 } …,让这个方法接受的价值“selectedPlayer”: “modifyPlayerScore”:函数(selectedPlayer){ / /代码在这里 } 然后,在该方法的功能,重新创建更新函数,我们刚才删除: 方法对131 “modifyPlayerScore”:函数(selectedPlayer){ PlayersList。更新(selectedPlayer { $ . n:行情):{得分:5 } }); } 基于此代码,“给5分”按钮将正常工作。使更多的方法 不过,灵活返回点击。增加事件和通过“5”的第三个参数 流星。调用语句: 的点击。增量”:函数(){ var selectedPlayer = Session.get(“selectedPlayer”); 流星。调用(‘modifyPlayerScore selectedPlayer 5); } 允许接受这个第三个参数的方法: “modifyPlayerScore”:函数(selectedPlayer scoreValue){ PlayersList。更新(selectedPlayer { $ . n:行情):{得分:5 } }); } 取代“5”的价值,在这个新创建的引用的方法 “scoreValue”属性: “modifyPlayerScore”:函数(selectedPlayer scoreValue){ PlayersList。更新(selectedPlayer { $ . n:行情):{得分:scoreValue } }); } 由于这一变化,现在的方法是足够灵活,我们可以用它来“给 5分”按钮和“5分”按钮。 这里有… 首先,从内部点击删除更新函数。衰减事件: 的点击。减量”:函数(){ var selectedPlayer = Session.get(“selectedPlayer”); } 第二,一颗流星。调用语句在这个事件: 的点击。减量”:函数(){ var selectedPlayer = Session.get(“selectedPlayer”); Meteor.call(“modifyPlayerScore”); } 第三,通过“selectedPlayer”变量的值: 方法对132 的点击。减量”:函数(){ var selectedPlayer = Session.get(“selectedPlayer”); 流星。调用(modifyPlayerScore,selectedPlayer); } 第四,通过“5”的价值,而不只是“5”: 的点击。减量”:函数(){ var selectedPlayer = Session.get(“selectedPlayer”); 流星。调用(‘modifyPlayerScore selectedPlayer 5); } 看到我们所做的吗? 我们已经取得了如此“modifyPlayerScore”方法的效用取决于我们通过 第三个参数: 1。如果我们通过一个“5”,更新函数增量的值 “分数”字段。 2。如果我们通过一个“5”,更新函数递减的价值 “分数”字段。 因此,该方法允许代码既灵活又安全。 我们有相同的安全缺陷前一节中,一个用户可以输入 下面的命令在控制台修改数据库中的任何球员的得分: 流星。调用(‘modifyPlayerScore’,‘8 sad8a90d8s9ad’,100); 但解决方案也是一样的。 从这只改变方法的内容: “modifyPlayerScore”:函数(selectedPlayer scoreValue){ PlayersList。更新(selectedPlayer { $ . n:行情):{得分:scoreValue } }); } …: “modifyPlayerScore”:函数(selectedPlayer scoreValue){ var currentUserId = Meteor.userId(); PlayersList。更新({ _id:selectedPlayer createdBy:currentUserId }, { $ . n:行情):{得分:scoreValue } }); } 再次,我们检索当前登录用户的惟一的ID,并在更新 正在更新功能,确保玩家“属于”用户。如果登录用户 并不“拥有”的球员,球员的文档不会被发现的更新功能。 方法对133 总结 在这一章,我们了解到: •在默认情况下,有可能为用户插入、更新和删除数据的收集 使用JavaScript控制台。这对于开发方便,但存在安全风险 部署web应用程序。 •修复这个安全风险,我们必须从客户端数据库相关代码, 服务器的信任的环境。在这里,用户不会有任何直接访问(或 控制)数据库。 •这个安全风险是包含在一个“没有安全感”包。通过移除这个包, 应用程序将变得更加安全,但它也会休息,因为没有一个databaserelated 功能将工作。 •通过使用方法,我们能够编写代码在服务器上运行后第一个被触发 从客户端。这是我们如何修复项目的破碎功能。 •创建方法,我们可以在方法中定义块,然后触发 从其他地方的代码使用流星。调用语句。 •我们可以从流星传递数据。调用语句和方法,让我们 使用提交的数据表单内的方法。 •用户可以执行客户端流星。通过控制台调用语句,所以我们需要 注意这些语句允许用户做什么。 •方法不仅适用于安全。他们也有用结合相似的块 的功能到一个小的和可重复的代码片段。 流星的更深层次的理解: •在一个新项目,首先删除“不安全”计划,从一开始,地方 里面所有的数据库相关代码的方法。 在其当前状态查看代码,查看GitHub提交。 结构 在本书中,我们把所有的项目的代码仅仅三个文件: •leaderboard.html •leaderboard.js •leaderboard.css 这使得我们关注的基本面与流星没有构建软件 担心代码是如何组织的,该项目是非常简单的,所以我们需要不 需要其他文件,但: 1。在构建大型应用程序,是有意义的传播项目的代码在一个 数量的文件。 2。流星有许多公约组织项目的文件。 在我们继续之前,有两个问题需要考虑: 首先,流星没有硬性规定如何构造一个项目。有 流星鼓励某些准则,但没有严格的,你必须做的。你的喜好 最终在控制。 第二,人们仍然找出最佳实践在处理流星。因此, 没有理由形式教条的观点项目“应该”是如何构造的。允许 自己的实验。 这一章也不同,我们不会重组项目step-bystep排行榜。 相反,我们将讨论结构的原则,这些原则,这就是你的工作 付诸实践。 不过别担心。 基于我们覆盖到目前为止,处理如何构造一颗流星 应用程序将是小菜一碟。 134年 结构135 你的项目,你的选择 就像我说的,流星没有硬性规定如何组织一个项目。它不 关心如何组织你的文件和文件夹,如果你想创建一个大型项目 只是三个文件,你可以。 不过,与这种灵活性带来选择的矛盾: 如果你不局限于精确的规则,如何构建您的项目吗? 如果你是一个开发人员开始,您的项目结构尽可能简单的只要你 可以。这意味着传播您的代码在仅仅三个文件——HTML,JavaScript,和CSS 文件,直到这些文件变得过于臃肿的轻松地管理。这是罕见的一个实际的应用 包含在这样一个小结构,但如果你只是开始使用流星,它是 不生产为“完美”的结构。 仍然阅读这一章,有一些重要的约定要注意——但不要 觉得有必要实现每一个细节。最佳实践更容易学习一次 基本面已经吸收了,只要你是一个初学者,你可以变得很糟。 如果你不是一个开发人员,这意味着开始,如果你有网站开发经验, 和没有任何麻烦连同这本书,那么你会有一个简单的时间 实现约定我们要讨论。 结构136 脂肪薄文件,文件 当创建一个流星应用程序时,项目的文件可以作为“瘦”或“脂肪”,因为我们想要的 他们是。这意味着: 1。我们可以传播许多文件的代码。 2。我们可以包很多每个文件(或小)代码。 例如,让我们考虑一下”排行榜。html文件。不是脂肪,但它确实包含了 三个组件,虽然连接,不需要包含在单一文件: •页面的HTML结构(头部标签,身体标签等)。 •“排行榜”模板。 •“addPlayerForm”模板。 如果这个项目变得越来越大,这将使这些组件拆分为三个 单独的文件。例如,你可能会想: 1。离开的HTML结构”排行榜。html文件。 2。把“排行榜”的“leaderboardList模板。html文件。 3所示。移动模板,一个“addPlayerForm addPlayerForm。html文件。 因此,它会更容易导航项目的文件因为每个文件的名称 暗示这文件包含什么。 需要澄清的是: 1。没有额外的步骤。把代码项目,无论你想要的 流星将知道如何把片段组合在一起。 2。文件名称是任意的。有一些“特殊”的文件名需要注意的,但是 一般来说,名字的文件,只要你喜欢就好。 你也可以将文件在文件夹和子文件夹(深层结构),但在那里 某些约定,鼓励某些命名这些文件夹的方法。 结构137 文件夹的约定,第1部分 很多内部的代码”排行榜。js”isClient条件内的文件。如果我们传播 这段代码在多个文件,它会不雅的重用这个条件 一次。 幸运的是,流星已经约定,任何的代码放在一个文件夹命名为“客户端” 只会在客户端上运行。 为了演示这个: 1。创建一个文件夹命名为“客户”在您的项目的文件夹。 2。在该文件夹中创建一个JavaScript文件。 3所示。剪切和粘贴的客户端代码”排行榜。js文件到新的文件,但是 没有isClient条件。 在保存文件时,应用程序将继续正常工作。 因为这个约定,最好是将模板,事件,助手,Meteor.subscribe 函数在一个“客户端”文件夹中。 相反,流星有约定的任何代码放置在一个文件夹命名 “服务器”只会在服务器上运行。这是我们地方项目的方法,和 流星。发表声明。 洗牌代码在排行榜内部应用程序之后,唯一的,左内 原始”排行榜。js文件将被声明,创建“PlayersList”集合。我们 希望这段代码运行在客户端和服务器,所以一定要离开这个声明 在“客户机”和“服务器”文件夹。一个常见的惯例是将这段代码在一个 ”集合。js文件,但是这个文件名字没有特别的意义。 结构138 文件夹约定,第2部分 当开始使用流星,大多数项目的文件可能会在“客户端” 或“服务器”文件夹。然而,一些其他的文件夹名称,可用于不同的 用途: •文件存储在一个“私人”文件夹只能访问的代码的执行 服务器。这些文件将永远不会访问用户。 •文件存储在一个“公共”文件夹是游客服务。这些文件是图片,图标, 和“机器人。txt文件。 •文件存储在一个“自由”文件夹其他文件之前加载。 但如果这一切似乎记得太多,不要害怕。这些细节是值得了解的 未来的参考,但这将是一段时间你需要付诸实施了。目前, 很好关注基础知识。 结构139 样板结构 学习如何结构的一种有效方式流星项目向其他开发人员学习 有可能遇到的许多问题有一天,你会遇到你。 例如,“铁”工具从克里斯事件化思想的源泉: 命令行脚手架流星应用程序的工具。它会自动创建 项目的结构,文件和样板代码。 这个工具可以用来快速创建一个项目使用以下结构: 我的app / .iron / json bin / 构建/ 配置/ 开发/ env.sh settings.json app / 客户端/ 集合/ lib / 样式表/ 模板/ head.html lib / 集合/ 控制器/ methods.js routes.js 包/ 私人/ 公共/ 服务器/ 集合/ 控制器/ lib / methods.js publish.js bootstrap.js 你会发现每件事都有它的位置。有文件夹集合和样式表 模板和其他组件的一个项目。 结构140 这是最好的方法构造一颗流星项目吗? 对一些人来说,它可能是。 我认为这有点复杂的人与流星刚刚开始,但当 你准备搬到一个更大的项目,它可能正是你需要管理 较大的基础代码。 在这个阶段,重点不是做出任何硬性的决定对你的偏好。但它 帮助了解什么至少是可能的。 其他样板值得一试,学习包括meteor-boilerplate和空白。 结构141 总结 在这一章,我们了解到: •流星并不在项目执行精确的文件结构。有简单的约定 我们鼓励遵守为了我们自己的利益。 •通过命名特定文件夹,在某些方面,我们能够避免编写一些应用程序 逻辑基于流星如何处理这些文件夹。 流星的更深层次的理解: •搜索别人的流星在GitHub,看看真实的项目 应用程序的结构。 •想象你创建一个博客应用程序像WordPress。你会如何结构 该应用程序?计划在一张纸上。 在其当前状态查看代码,查看GitHub提交。 部署 在本书中,我们取得了很多的进步。我们决定在项目建设,创建 所有的基本功能,添加了一些额外的细节,甚至谈到了几个 常见的安全问题。 因此,我们准备部署到web的应用程序。 在这里我们可以分享我们的创造与世界然后等待成群的陌生人 奇迹在我们的天才。但部署并不是简单的上传文件到web服务器。 有更多的参与。 这是一个广泛的部署过程的概述: 1。创建一个服务器DigitalOcean等网站。 2。在该服务器上安装所需的软件(节点,MongoDB,等等)。 3所示。配置所有的安装软件。 4所示。项目的文件上传到服务器。 5。交叉你的手指,没有休息。 听起来很复杂,对吗? 不要担心,我有你覆盖。 在这本书的前两个版本,我解释的绝对基础部署流星 应用程序web但已经放在一起更全面的指导,分开 从这本书。 你可以免费在线阅读: meteortips.com/deployment-tutorial 如果你想尽快部署的东西,你只需要阅读第一 两个章,但是当你准备发射比throwntogether更有趣的东西 轻轻原型,这本书将指导您完成每一步的过程中, 与其他我发布在网上,你也可以看到很多的更新 部署实践的变化和发展。 也就是说,如果你不希望将应用程序部署到世界,这很好。 没有什么关于部署,你需要知道这一点。这个过程是相当 开发过程和截然不同的东西,直到你已经开发了应用程序,你的 时间是更好的在一个文本编辑器,编写代码,使事情。 142年 结论 祝贺你。你已经达到了这本书的最后一页。在第一章,就像我说的 这本书不是汤姆。有更多了解建筑与流星很酷的东西 框架。 这就是我建议: 1。如果你还没有,实际上我们已经构建排行榜应用程序 讨论这本书。没有更好的方法来学习如何比通过编写代码 每一行,循序渐进。 2。看流星的官方文档。你可能不理解每一点 它,但它确实提供了洞察如何以及为什么某些特性工作的方式做。 3所示。遵循“如何正确学习流星”的路线图。这是一个彻底的课程 成为一个全面的流星开发者(那就推荐这个 书)。 如果你还没有,请访问meteortips.com并注册电子邮件时事通讯。这是 最好的方法是不管我工作,帮助你做出更大、更快 进步与流星。 这就是现在。 祝你好运,和说话很快。 €”大卫·特恩布尔 注:如果你喜欢这本书,在Amazon.com上留下评论。你的支持让我 花更多的时间来研究新材料。 0 - [你的第一个Meteor应用](/tags/%E4%BD%A0%E7%9A%84%E7%AC%AC%E4%B8%80%E4%B8%AAMeteor%E5%BA%94%E7%94%A8/) [**Newer** 如何同步Hexo网站到github ](/posts/54923/)[**Older** Meteor入门 ](/posts/49028/) ### Categories - [我的作品](/categories/%E6%88%91%E7%9A%84%E4%BD%9C%E5%93%81/)3 - [敏捷开发](/categories/%E6%95%8F%E6%8D%B7%E5%BC%80%E5%8F%91/)1