现如今,虽然多数的web应用都使用了大量的JavaScript,但如何保持客户端功能的专注性、健壮性和可维护性依然是一个很大的挑战。
尽管其它编程语言和系统都已经将关注分离和DRY这样的基本原则视为理所当然的宗旨,但往往在进行浏览器端应用开发的时候,这些原则就被忽视了。
造成这一现象的部分原因是JavaScript语言本身就在不断挣扎的历史,在很长的一段时间内,它都难以获得开发者的认真关注和对待。
而更重要的原因或许是源于服务端与客户端的差异造成的。虽然在这方面已经有大量的架构风格方面的概念,例如ROCA,阐述了如何管理这种差异的方式。但还是缺乏如何实现这些概念的具体步骤的指南1。
这些原因经常导致前端代码的高度过程化并且相对缺乏结构性,这种直接的代码调用方式减少了调用的开销,从而简化了代码调用的复杂性,JavaScript和浏览器也是因为这一点原因而允许这种调用方式的存在。但很快,通过这种方式实现的代码就会变得得难以维护。
本文将通过一个示例为你展示某个简单的组件(widget)的演化过程,看看它是如何从一个庞大的、缺乏结构性的代码库进化为一个可重用的组件的。
对联系人进行过滤
这个示例组件的作用是对一个联系人列表通过名称进行过滤。它的最新成果以及它的全部演化过程都可以在这个GitHub代码库中找到。我们鼓励读者们对提交的代码进行审阅,并且留下宝贵意见。
按照渐进式增强的原则,我们首先从一个基础的HTML结构开始以描述所用到的数据。这里用到了h-card这个微格式(microformat),它能够起到语义化的作用,使得联系人的各种信息显得具有意义:
<!-- index.html --> <ul> <li class="h-card"> <img src="png/jake.png" alt="avatar" class="u-photo"> <a href="http://jakearchibald.com" class="p-name u-url">Jake Archibald</a> (<a href="mailto:jake@example.com" class="u-email">e-mail</a>) </li> <li class="h-card"> <img src="png/christian.png" alt="avatar" class="u-photo"> <a href="http://christianheilmann.com" class="p-name u-url">Christian Heilmann</a> (<a href="mailto:christian@example.com" class="u-email">e-mail</a>) </li> <li class="h-card"> <img src="png/john.png" alt="avatar" class="u-photo"> <a href="http://ejohn.org" class="p-name u-url">John Resig</a> (<a href="mailto:john@example.com" class="u-email">e-mail</a>) </li> <li class="h-card"> <img src="png/nicholas.png" alt="avatar" class="u-photo"> <a href="http://www.nczonline.net" class="p-name u-url">Nicholas Zakas</a> (<a href="mailto:nicholas@example.com" class="u-email">e-mail</a>) </li> </ul>
有一点请注意,在这里我们并不关心这个DOM结构是基于server端生成的HTML代码,或是由其它组件生成的,只要保证在初始化时,我们的组件能够依赖于这个基础结构就够了。这一结构实际上为表单项构成了一个基于DOM的数据结构 [{ photo, website, name, e-mail }]。
有了这个基础结构之后,我们就可以开始实现我们的组件了。第一步是为用户提供一个输入字段,以输入联系人名称。虽然它并不属于DOM结构的契约,但我们的组件仍然要负责创建它并动态地加入到DOM结构中去(毕竟,如果没有我们的组件,那么添加这个字段就完全没有任何意义了)。
// main.js var contacts = jQuery("ul.contacts"); jQuery('<input type="search" />').insertBefore(contacts);
(我们在这里仅是出于便利性而使用了jQuery,同时也考虑到它的广泛使用性。如果使用其它的DOM操作类库,也是出于同样的原因。)
这个JavaScript文件本身以及它所依赖的jQuery文件都会在HTML文件的底部进行引用。
接下来开始加入所需的功能,对于那些不符合这个新建的字段中的输入名称的联系人,这个组件会将它们隐藏起来:
// main.js var contacts = jQuery("ul.contacts"); jQuery('<input type="search" />').insertBefore(contacts). on("keyup", onFilter); function onFilter(ev) { var filterField = jQuery(this); var contacts = filterField.next(); var input = filterField.val(); var names = contacts.find("li .p-name"); names.each(function(i, node) { var el = jQuery(node); var name = el.text(); var match = name.indexOf(input) === 0; var contact = el.closest(".h-card"); if(match) { contact.show(); } else { contact.hide(); } }); }
(引用一个分离的、具名的函数,比起定义一个匿名函数来说,通常会使得回调函数更便于管理。)
请注意,这个事件处理函数依赖于特定的DOM环境,它取决于触发这个事件的元素(它的执行上下文会映射到this指针上)。我们将从这个元素开始遍历DOM结构,以访问联系人列表,并找出所有包含名称的元素(这是由微格式的语义所定义的)。如果某个名称的开头部分与当前输入的内容不匹配,我们就再次向上遍历,将相应的容器元素隐藏起来,否则的话,就要保证该元素依然可见。
查看本栏目更多精彩内容:http://www.bianceng.cnhttp://www.bianceng.cn/webkf/script/
以上是小编为您精心准备的的内容,在的博客、问答、公众号、人物、课程等栏目也有的相关内容,欢迎继续使用右上角搜索按钮进行搜索jquery
, 结构
, 代码
, 组件
, contacts
一个
前端模块化组件化开发、js模块化开发的组件、javascript模块化开发、javascript组件开发、javascript组件化开发,以便于您获取更多的相关知识。