这是三部分系列中的第二部分,将教您如何使用 CanJS 和 jQuery 在 JavaScript 中构建联系人管理器应用程序。学完本教程后,您将拥有使用 CanJS 构建自己的 JavaScript 应用程序所需的一切!
在第一部分中,您创建了显示联系人所需的模型、视图和控件,并使用了模拟 REST 服务的固定装置。
在这一部分中,您将:
您将添加到第一部分中的源文件,因此如果您还没有这样做,请先跟上。当你准备好时我会在这里。
路由有助于管理单页 JavaScript 应用程序中的浏览器历史记录和客户端状态。
路由有助于管理单页 JavaScript 应用程序中的浏览器历史记录和客户端状态。 URL 中的哈希包含应用程序读取和写入的属性。应用程序的各个部分可以侦听这些更改并做出相应的反应,通常会更新当前页面的部分内容而不加载新页面。
can.route
是一个特殊的可观察对象,它更新并响应 window.location.hash
中的更改。使用 can.route
将 URL 映射到属性,从而生成漂亮的 URL,例如 #!filter/all
。如果没有定义路由,则哈希值只会序列化为 URL 编码表示法,如 #!category=all
。
在此应用程序中,路由将用于按类别过滤联系人。将以下代码添加到您的 contacts.js
文件中:
can.route( 'filter/:category' ) can.route('', {category: 'all' })
第一行创建一个带有 category
属性的路由,您的应用程序将能够读取和写入该属性。第二行创建一个默认路由,将 category
属性设置为 all
。
A Model.List
是模型实例的可观察数组。当您定义 Model
(如 Contact
)时,会自动创建该类型模型的 Model.List
。我们可以扩展这个创建的 Model.List
以添加对模型实例列表进行操作的辅助函数。
Contact.List
将需要两个辅助函数来过滤联系人列表并报告每个类别中有多少联系人。将其添加到 Contact.List
将需要两个辅助函数来过滤联系人列表并报告每个类别中有多少联系人。将其添加到 contacts.js
紧跟在 Contact
紧跟在 Contact
模型之后:
Contact.List = can.Model.List({ filter: function(category){ this.attr('length'); var contacts = new Contact.List([]); this.each(function(contact, i){ if(category === 'all' || category === contact.attr('category')) { contacts.push(contact) } }) return contacts; }, count: function(category) { return this.filter(category).length; } });
这里的两个辅助函数是:
filter()
循环访问列表中的每个联系人,并返回类别内联系人的新 Contact.List
。 this.attr('length')
包含在此处,因此当我们在视图中使用此帮助程序时,EJS 将设置实时绑定。count()
使用 filter()
辅助函数返回类别中的联系人数量。由于 this.attr('length')
在 filter()
中,当我们在视图中使用此帮助器时,EJS 将设置实时绑定。 如果您要在 EJS 中使用帮助程序,请在列表或实例属性上使用
attr()
来设置实时绑定。
接下来,您将修改 contactsList.ejs
视图,以根据哈希中的类别属性过滤联系人。在 contactsList.ejs
视图中,将传递给 list()
帮助器的参数更改为 contacts.filter(can.route.attr('category'))
。完成后,您的 EJS 文件应如下所示:
<ul class="unstyled clearfix"> <% list(contacts.filter(can.route.attr('category')), function(contact){ %> <li class="contact span8" <%= (el)-> el.data('contact', contact) %>> <div class=""> <%== can.view.render('contactView', {contact: contact, categories: categories}) %> </div> </li> <% }) %> </ul>
在第二行,使用 can.route
中的当前类别调用 filter()
。由于您在 filter()
和 can.route
中使用了 can.route
中的当前类别调用 filter()
。由于您在 filter()
和 can.route
中使用了 attr()
,因此当其中任何一个发生更改时,EJS 将设置实时绑定以重新渲染您的 UI。
现在您应该清楚实时绑定的强大功能了。通过对视图进行轻微调整,应用程序的 UI 现在不仅与联系人列表完全同步,还与路线中定义的类别属性完全同步。
当哈希中的类别属性更改时,联系人将被过滤。现在您需要一种方法来列出所有可用类别并更改哈希值。
首先,创建一个新视图来显示类别列表。将此代码保存为 filterView.ejs
在 views
文件夹中:
<ul class="nav nav-list"> <li class="nav-header">Categories</li> <li> <a href="javascript://" data-category="all">All (<%= contacts.count('all') %>)</a> </li> <% $.each(categories, function(i, category){ %> <li> <a href="javascript://" data-category="<%= category.data %>"><%= category.name %> (<%= contacts.count(category.data) %>)</a> </li> <% }) %> </ul>
让我们看一下这段代码中的几行,看看它们做了什么:
<% $.each(categories, function(i, category){ %>
$.each
循环遍历类别并为每个类别执行回调。
<a href="javascript://" data-category="<%= category.data %>"><%= category.name %> (<%= contacts.count(category.data) %>
每个链接都有一个 data-category
属性,该属性将被拉入 jQuery 的数据对象中。稍后,可以使用 <a></a>
标记上的 .data('category')
来访问该值。类别的名称和联系人数量将用作链接测试。实时绑定是根据联系人数量设置的,因为 count()
调用 filter()
其中包含 this.attr('length')
。
can.Control
监听事件
创建实例时,控件会自动绑定看起来像事件处理程序的方法。事件处理程序的第一部分是选择器,第二部分是您要侦听的事件。选择器可以是任何有效的 CSS 选择器,事件可以是任何 DOM 事件或自定义事件。因此,像 'a click'
这样的函数将监听控件元素内任何 <a></a>
标记的点击。
Control 使用事件委托,因此您不必担心在 DOM 更改时重新绑定事件处理程序。
通过将此代码添加到 contacts.js
紧随 Contacts
控件之后来创建管理类别的控件:
Filter = can.Control({ init: function(){ var category = can.route.attr('category') || "all"; this.element.html(can.view('filterView', { contacts: this.options.contacts, categories: this.options.categories })); this.element.find('[data-category="' + category + '"]').parent().addClass('active'); }, '[data-category] click': function(el, ev) { this.element.find('[data-category]').parent().removeClass('active'); el.parent().addClass('active'); can.route.attr('category', el.data('category')); } });
让我们检查一下您刚刚创建的“Filter”控件中的代码:
this.element.html(can.view('filterView', { contacts: this.options.contacts, categories: this.options.categories }));
就像在 Contacts
控件中一样,init()
使用 can.view()
来呈现类别,并使用 html()
将其插入到控件的元素中。
this.element.find('[data-category="' + category + '"]').parent().addClass('active');
查找与当前类别相对应的链接,并将“active”类添加到其父元素。
'[data-category] click': function(el, ev) {
监听与选择器 [data-category]
匹配的任何元素上的 click
事件。
this.element.find('[data-category]').parent().removeClass('active'); el.parent().addClass('active');
从所有链接中删除“活动”类,然后向单击的链接添加“活动”类。
can.route.attr('category', el.data('category'));
使用 jQuery 数据对象中所单击的 <a></a>
的值更新 can.route
中的类别属性。
就像第一部分中的 Contacts
控件一样,您需要创建 Filter
控件的新实例。更新您的文档就绪函数,如下所示:
$(document).ready(function(){ $.when(Category.findAll(), Contact.findAll()).then(function(categoryResponse, contactResponse){ var categories = categoryResponse[0], contacts = contactResponse[0]; new Contacts('#contacts', { contacts: contacts, categories: categories }); new Filter('#filter', { contacts: contacts, categories: categories }); }); })
通过此更改,将在 #filter
元素上创建 Filter
控件的实例。它将传递联系人和类别列表。
现在,当您在浏览器中运行应用程序时,您将能够通过单击右侧的类别来过滤联系人:
这就是第二部分的全部内容!以下是我们所取得的成就:
在第三部分中,您将更新现有控件以允许编辑和删除联系人。您还将创建一个新的控件和视图,以便您添加新的联系人。
迫不及待想了解更多信息?该系列的第三部分已发布在这里!
以上是深入了解CanJS:第二部分的详细内容。更多信息请关注PHP中文网其他相关文章!