< / div >
®< / span >< / div >
< / span >
世界顶尖人才,点播 ®< / span >< / div >< / div >< / div >< / div >< / div >< / div >
< / div >< / div >

Toptal, LLC版权所有

< / div >< / div >< / div >\n\n\n

如果这看起来很眼熟,那是因为安伯.js使用 车把 模板,它有一个非常简单的语法和帮助,但不允许重要的逻辑(如.g.(条件条件中的ORing或ding项).

\n\n

在上面的模板中, 我们遍历模型(前面通过到包含所有艺术家的数组的路由设置)并遍历其中的每个项目, 我们呈现一个链接,将我们带到 艺术家.歌曲 那个艺术家的路线. 该链接包含艺术家名称. 的 #每一个 车把中的helper将其内部的作用域更改为当前项,因此 {{名称}} 总是提到目前正在迭代的美工的名字吗.

\n\n

嵌套路由用于嵌套视图

\n\n

上面的代码片段中还有一个有趣的地方: {{插座}},它指定模板中可以呈现内容的位置. 当嵌套路由时, 模板为外层, 首先呈现资源路由, 接着是内线, 将其模板内容呈现到 {{插座}} 由外部路由定义. 这就是这里发生的事情.

\n\n

按照惯例,所有路由都把自己的内容呈现到同名的模板中. 以上, data-template-name 属性为 艺术家 这意味着它会被渲染为外部路线, 艺术家. 它为右面板的内容指定了一个出口,内部路由将进入该出口。 艺术家.指数 渲染其内容:

\n\n
\n
\n\n

总之,一条路线(艺术家)在左侧栏中呈现其内容,其模型是艺术家列表. 另一条路线, 艺术家.指数 控件提供的槽中呈现它自己的内容 艺术家 template. 它可以获取一些数据作为模型,但这里我们只想显示静态文本, 所以我们不需要.

\n\n
\n相关: 8基本灰烬.js面试问题\n< / div >\n\n

创造一个艺术家

\n\n

第1部分:数据绑定

\n\n

接下来,我们希望能够创造艺术家,而不仅仅是看一个无聊的列表.

\n\n

当我展示的时候 艺术家 模板,渲染艺术家列表,我骗了一点. 我把上面的部分剪掉,把重点放在重要的部分上. 现在,我把它加回去:

\n\n
\n
\n\n

我们使用烬助手, input,使用type text来呈现简单的文本输入. 在里面,我们 绑定 的文本输入值 新名称 备份此模板的控制器的属性, 艺术家Controller. 的后果, 当输入的值属性发生变化时(换句话说, 当用户在其中输入文本时 新名称 属性将保持同步.

\n\n

我们也知道 create艺术家 操作应该在按钮被点击时被触发. 最后,我们将按钮的禁用属性绑定到 禁用 控制器的属性. 那么控制器是什么样的呢?

\n\n
应用程序.artstscontroller = 灰烬.数组Controller.扩展({\n  新名称:”,\n  禁用:function() {\n    回归灰烬.isEmpty(这.(新名称));\n  }.属性(新名称)\n});\n
\n\n

新名称 在开始时设置为空,这意味着文本输入将是空的. (还记得我说过的绑定吗? 试着改变 新名称 然后把它作为文本反射到输入框中.)

\n\n

禁用 是这样实现的,当输入框中没有文本时,它将返回 真正的 因此按钮将被禁用. 的 .财产 最后的调用使它成为一个“计算属性”,烬蛋糕的另一个美味的切片.

\n\n

计算属性 依赖于其他属性的属性本身是“正常的”或可计算的吗. 灰烬会缓存这些属性的值,直到其中一个相关属性发生变化. 然后重新计算计算属性的值并再次缓存它.

\n\n

下面是上述过程的可视化表示. 总而言之:当用户输入艺术家的名字时 新名称 属性更新,然后是 禁用 属性,最后将艺术家的名字添加到列表中.

\n\n

\"\"

\n\n

绕路:真理的单一来源

\n\n

想想看. 借助绑定和计算属性,我们可以将(模型)数据建立为 真理的单一来源. 以上, 新艺术家名称的更改会触发控制器属性的更改, 进而触发禁用属性的更改. 当用户开始输入新艺术家的名字时,按钮就会被启用,就像变魔术一样.

\n\n

系统越大,我们从“单一真相来源”原则中获得的杠杆作用就越大. 它使我们的代码保持整洁和健壮,并且使我们的属性定义更具声明性.

\n\n

其他一些框架也强调将模型数据作为事实的单一来源,但要么没有灰烬做得那么好,要么没有做得那么彻底. 例如,角有双向绑定——但没有计算属性. It can “emulate” 计算 properties through simple functions; the problem here is that it has no way of knowing when to refresh a “计算 财产” 和 thus resorts to dirty checking 和, 反过来, 导致性能损失, 尤其是在大型应用程序中.

\n\n

如果您想了解更多有关该主题的信息,我建议您阅读 恶魔鳟鱼的博客 对于较短的版本或 这个Quora问题 为了让双方核心开发者参与更长的讨论.

\n\n

第2部分:操作处理程序

\n\n

让我们回去看看 create艺术家 动作是在它被触发后创建的(在按下按钮之后):

\n\n
应用程序.艺术家路线 = 灰烬.路线.扩展({\n  ...\n  行动:{\n    create艺术家:函数(){\n      Var name = 这.get(控制器).(新名称);\n\n      灰烬.$.ajax (http://localhost: 9393 /艺术家,{\n        类型:“文章”,\n        数据类型:json,\n        数据:{name: name},\n        背景:这个,\n        成功:function(data) {\n          var artist = 应用程序.艺术家.createRecord(数据);\n          这.梅尔('艺术家').推Object(艺术家);\n          这.get(控制器).集(新名称,”);\n          这.transitionTo(“艺术家.歌”,艺术家);\n        },\n        错误:function() {\n          alert('未能保存艺术家');\n        }\n      });\n    }\n  }\n});\n
\n\n

操作处理程序需要包装在 行动 对象,可以在路由、控制器或视图上定义. 我选择在这里的路由中定义它,因为动作的结果并不局限于控制器,而是, “全球”.

\n\n

这里没有什么特别的. 后端通知我们保存操作成功完成后, 我们做三件事, 在顺序:

\n\n
    \n
  1. 将新的艺术家添加到模板(所有艺术家)的模型中,以便它被重新渲染,并且新艺术家显示为列表的最后一项.
  2. \n
  3. 清除输入字段 新名称 绑定,使我们不必直接操作DOM.
  4. \n
  5. 转到新路线(艺术家.歌曲),将新创建的艺术家作为这条路线的模型. transitionTo 在内部路线之间移动的方式. ( 链接到 Helper通过用户操作来完成这个任务.)
  6. \n
\n\n

展示艺术家的歌曲

\n\n

我们可以通过点击艺术家的名字来显示艺术家的歌曲. 我们也让艺术家进来,他将成为新路线的模特. 如果模型对象就这样被传入,则 模型 路由的钩子将不会被调用,因为不需要解析模型.

\n\n

这里的活动路径是 艺术家.歌曲 因此控制器和模板将是 艺术家SongsController艺术家/歌曲分别. 我们已经看到了模板是如何被渲染到 艺术家 模板,这样我们就可以只关注手头的模板:

\n\n
\n
\n\n

请注意,我删除了创建新歌的代码,因为它与创建新艺术家的代码完全相同.

\n\n

歌曲 属性根据服务器返回的数据在所有艺术家对象中设置. 这一过程的确切机制并没有引起科学家的兴趣\n当前讨论. 现在,我们知道每首歌都有一个标题和评分就足够了.

\n\n

标题直接显示在模板中,评级由星星表示 StarRating 视图. 我们来看看.

\n\n

星级评定工具

\n\n

歌曲的评分在1到5之间,并通过视图显示给用户, 应用程序.StarRating. 视图可以访问它们的上下文(在本例中是歌曲)和它们的控制器. 这意味着他们可以读取和修改它的属性. 这与另一个烬构建块形成对比, 组件, 它们是孤立的, 可重用的控件,只能访问传递给它们的内容. (我们也可以在这个例子中使用星级评价组件.)

\n\n

让我们看看视图如何显示星星的数量,并在用户点击其中一个星星时设置歌曲的评级:

\n\n
应用程序.StarRating =灰烬.视图.扩展({\n  一会:“评级-panel”,\n  templateName:“星级”,\n\n  评级:灰烬.计算.别名(“上下文.评级”),\n  完整的Stars:灰烬.计算.别名(“评级”),\n  numStars:灰烬.计算.别名(“maxRating”),\n\n  *: function() {\n    Var评级= [];\n    var 完整的Stars = 这.starRange(1,这.(“完整的Stars”),“满”);\n    var emptyStars = 这.starRange(这.get('完整的Stars') + 1,这.(“numStars”),“空”);\n    数组.原型.推.应用(评级,完整的Stars);\n    数组.原型.推.应用(评级,emptyStars);\n    返回评级;\n  }.产权(“完整的Stars”、“numStars”),\n\n  starRange:函数(start, end, type) {\n    var 星星Data = [];\n    for (i = start; i <= end; i++) {\n      星星Data.Push ({评级: i, 完整的: type === '完整的'});\n    };\n    返回星星Data;\n  },\n  (...)\n});\n
\n\n

评级, 完整的StarsnumStars 我们之前讨论过的计算属性是 禁用 的性质 艺术家Controller. 上面,我使用了一个所谓的计算属性宏,其中大约有十几个是在灰烬中定义的. 它们使典型的计算属性更简洁,更不容易出错(编写)。. 我设置 评级 是对上下文的评价(因此也是对歌曲的评价),而我定义了 完整的StarsnumStars 属性,以便它们在星级评定小部件的上下文中更好地阅读.

\n\n

星星 方法是主要的吸引力. 它返回一个星号数据数组,其中每个项目都包含一个 评级 属性(从1到5)和标志(完整的)来表示星星是否满了. 这使得在模板中遍历它们变得非常简单:

\n\n
\n
\n\n

这段代码包含几个注意事项:

\n\n
    \n
  1. 首先, 每一个 Helper指定它\n通过前缀使用视图属性(而不是控制器上的属性)\n带有的属性名 视图.
  2. \n
  3. 第二, class 属性\n分配的混合动态类和静态类. 任何以a为前缀的 : 变成了一个\n静态类,而 全部:glyphicon-star: glyphicon-star-empty 符号就像\nJavaScript中的三元运算符:如果完整的属性为真,\nthe first class should be assigned; if 不, the second.
  4. \n
  5. 最后,当单击标记时, setRating action应该被触发——但是灰烬会在视图中查找它, 不是路由或控制器, 就像创造一个新的艺术家一样.
  6. \n
\n\n

因此,在视图上定义了操作:

\n\n
应用程序.StarRating =灰烬.视图.扩展({\n  (...)\n  行动:{\n    setRating: function() {\n      var newRating = $(事件.目标).数据(“评级”);\n      这.设置(“评级”,newRating);\n    }\n  }\n});\n
\n\n

我们从 评级 属性,然后将其设置为 评级 为了这首歌. 请注意,新评级不会在后端持久化. 基于我们创造美工的方式,实现这一功能并不是一件难事,它留给有动机的读者作为练习.

\n\n

总结一下

\n\n

我们已经品尝了前面提到的余烬蛋糕的几种成分:

\n\n
    \n
  • 我们已经看到了路由如何成为灰烬应用程序的关键,以及它们如何作为命名约定的基础.
  • \n
  • 我们已经看到了双向数据绑定和计算属性如何使模型数据成为事实的单一来源,并允许我们避免直接的DOM操作.
  • \n
  • 我们已经看到了如何以几种方式触发和处理动作以及如何构建一个自定义视图来创建一个控件 HTML的一部分.
  • \n
\n\n

很漂亮,不是吗?

\n\n

进一步阅读(和观看)

\n\n

关于烬的内容远远超过我在这篇文章中所能描述的. 如果你想看一个关于我如何构建上述应用程序的更先进版本和/或了解更多关于灰烬的视频系列, 你可以 加入我的邮件列表 每周获得文章或提示.

\n\n

我希望我已经激起了你对烬的更多了解.js和你远远超出了我在这篇文章中使用的示例应用程序. 当你继续了解烬.请务必看一下我们的 关于灰烬 Data的文章,以学习如何使用灰烬 - Data库. 玩得开心!

\n\n
\n相关: 灰烬.js和开发者常犯的8个错误\n< / div >\n","as":"div","isContentFit":真正的,"sharingWidget":{"url":"http://yv45.vig2.net/javascript/a-step-by-step-guide-to-building-your-first-ember-js-app","title":"你的第一个灰烬.js应用: A Comprehensive Tutorial","text":null,"providers":["linkedin","推特","脸谱网"],"gaCategory":null,"domain":{"name":"developers","title":"工程","vertical":{"name":"developers","title":"开发人员","publicUrl":"http://yv45.vig2.net/developers"},"publicUrl":"http://yv45.vig2.net/developers/blog"},"hashtags":"JavaScript,角JS,灰烬.js"}}> < /脚本