多应用+插件架构,代码干净,二开方便,首家独创一键云编译技术,文档视频完善,免费商用码云13.8K 广告
--- title: 响应式 slug: reactivity date: 0006/01/02 number: 6.5 points: 5 sidebar: true photoUrl: http://www.flickr.com/photos/ikewinski/9632550278/ photoAuthor: Mike Lewinski contents: 学习 Meteor 响应式代码依赖系统。|理解它的原理以及它如何声明代码。|学习使用高级代码来调用响应式数据。 paragraphs: 20 --- 如果说集合是 Meteor 的核心功能,那么**响应式**可以能让这个核心功能更强大。 集合从根本上改变你的应用程序的数据处理方式。从而不必手动检查数据更改(例如,通过一个 AJAX 调用),再根据这些变化去修改 HTML 页面,Meteor 可以随时检测到数据的更改,并将它无缝地应用到你的用户界面上。 让我们思考一下:在后台,当底层的数据集合被更新以后, Meteor 能够马上修改用户界面的**任何**部分。 这个实时性的方法是通过使用 `.observe()` ,当指向数据的指针发生改变时就会触发回调。我们可以通过这些回调去更改 DOM (我们的网页呈现的 HTML )。就像这样的代码: ~~~js Posts.find().observe({ added: function(post) { // when 'added' callback fires, add HTML element $('ul').append('<li id="' + post._id + '">' + post.title + '</li>'); }, changed: function(post) { // when 'changed' callback fires, modify HTML element's text $('ul li#' + post._id).text(post.title); }, removed: function(post) { // when 'removed' callback fires, remove HTML element $('ul li#' + post._id).remove(); } }); ~~~ 可能你已经知道这样的代码是如何把复杂的事情快速地进行处理。想象一下如果我们去修改帖子的**任何一个属性**,就会伴随着页面中帖子 `<li>` 标签的更改。当我们开始依赖于更多个数据信息的时候,甚至还可以进行更为复杂的处理,这些都能实时地进行。 <% note do %> ### 我们应该什么时候去使用 `observe()` ? 使用上述的模式有时候很有必要的,尤其是在处理第三方小部件的时候。比如,假设我们想要基于集合数据去实时添加或删除在地图上的位置(也就是说显示当前登录用户的位置)。 在这种情况下,为了让地图能跟 Meteor 的集合进行“交谈”,你就需要使用 `observe()` 的回调方法去应对数据变化。例如,你需要依赖其中 `added` 和 `removed` 的回调方法去调用地图 API 中的 `dropPin()` 或 `removePin()` 方法。 <% end %> ### 声明式方法 Meteor 为我们提供了一个更好的办法:声明式方法,它的核心就是响应式。这种声明让我们定义了对象之间的关系,并让他们保持同步,而我们就不必为每个的可能发生的修改去指定相应的行为。 这是一个强大的概念,因为有许多实时性的输入,都可能发生在我们不可预测的时间中。通过声明式方法去声明我们该如何基于响应式数据去呈现 HTML ,这样 Meteor 就可以完成对这些数据的监控工作,并且把用户界面直接与数据进行绑定。 总的来说,去代替 `observe` 的回调,Meteor 可以让我们这样写: ~~~html <template name="postsList"> <ul> {{#each posts}} <li>{{title}}</li> {{/each}} </ul> </template> ~~~ 然后获取我们的帖子列表: ~~~js Template.postsList.helpers({ posts: function() { return Posts.find(); } }); ~~~ 在后台,其实 Meteor 替我们使用了 `observe()` 的回调方法,并当响应式数据被更改的时候,对相关页面进行重新的渲染。 ### Meteor 的依赖跟踪:Computations Meteor 是一个实时性、响应式的框架,但并不是**所有**的代码在 Meteor App 里面都是响应式的。如果是这样,当有任何数据发生改变时,你的 App 都会自动进行重新运行。相反,响应式只是在特定区域的代码中发生,我们称这些区域为 **Computations** 。 换句话说, Computations 代码块是根据响应式数据的变化去运行。如果你有一个响应式数据源(例如,一个 Session 变量)并且希望及时去响应它,你需要建立一个 Computations。 请注意,你一般不需要显式地做到这一点,因为 Meteor 已经让每个模板去呈现它自己的 Computation (意思就是模板 Helper 中的代码和回调函数默认都是响应式的)。 Computations 用到的响应式数据源都会被它跟踪,这样就可以知道响应式数据什么时候发生变化。这是通过 Computations 中的 `invalidate()` 方法实现的。 Computations 一般只是简单地用来判断页面上的无效内容,这通常是发生在模板的 Computations(尽管模板 Computations 可能也会去做一些让页面更有效的工作)。当然如果你需要,你也可以使用更多 Computations 的功能,不过在实际中可能比较少用到。 ### 建立一个 Computations 现在我们去理解一下 Computations 背后的工作原理,实际上要设置一个 Computations 是出乎意料的简单。我们只需要在 `Tracker.autorun` 方法中加上需要的代码块,让它变成响应式的 Computations : ~~~js Meteor.startup(function() { Tracker.autorun(function() { console.log('There are ' + Posts.find().count() + ' posts'); }); }); ~~~ 注意我们需要把 `Tracker` 代码块放进 `Meteor.startup()` 块中,来确保它在 Meteor 完成加载 `Posts` 集合后只运行一次。 在后台,`autorun` 会创建一个 Computation ,当数据源发生变化的时候就会自动重新运行。这样我们就建立了一个非常简单的 Computation ,去把帖子的数量输出到控制台上。因为 `Posts.find()` 是一个响应式数据源,它将负责告诉 Computation 每次帖子数量发生变化的时候去重新运行。 ~~~js > Posts.insert({title: 'New Post'}); There are 4 posts. ~~~ 综上所述,我们可以把响应式数据通过一种很自然的方式与代码进行绑定,这样后台的依赖系统将会在合适的时间去重新运行这段代码。