下面一个列表,希望单击每一个list时,能够bootstrap alert.js出其index。想知道为什么下面的JS代码不起作用。大神指教

jQuery 基本原理
With contributions by James Padolsey, Paul Irish, and others.
See the GitHub repository for a complete history of
contributions.中文版由灰狐翻译团队完成:Allen、Hxgdzyuyi、Jack Hsing、Julian Wong、Leegorous、黎展波、Sky hx、Zengzhan(按字母顺序)
are free to copy, distribute, transmit, and remix this work, provided
you attribute the work to Rebecca Murphey as the original author and
reference . If you alter, transform, or build upon
this work, you may distribute the resulting work only under the same,
similar or a compatible license. Any of the above conditions can be
waived if you get permission from the copyright holder. For any reuse or
distribution, you must make clear to others the license terms of this
work. The best way to do this is with .
Table of ContentsList of Examples1.1. 1.2. 1.3. 2.1. 2.2. 2.3. 2.4. 2.5. 2.6. 2.7. 2.8. 2.9. 2.10. 2.11. 2.12. 2.13. 2.14. 2.15. 2.16. 2.17. 2.18. 2.19. 2.20. 2.21. 2.22. 2.23. 2.24. 2.25. 2.26. 2.27. 2.28. 2.29. 2.30. 2.31. 2.32. 2.33. 2.34. 2.35. 2.36. 2.37. 2.38. 2.39. 2.40. 2.41. 2.42. 2.43. 2.44. 2.45. 2.46. 2.47. 3.1. 3.2. 3.3. 3.4. 3.5. 3.6. 3.7. 3.8. 3.9. 3.10. 3.11. 3.12. 3.13. 3.14. 3.15. 3.16. 3.17. 3.18. 3.19. 3.20. 3.21. 3.22. 3.23. 3.24. 3.25. 3.26. 3.27. 3.28. 3.29. 3.30. 3.31. 3.32. 3.33. 3.34. 3.35. 4.1. 4.2. 4.3. 4.4. 4.5. 5.1. 5.2. 5.3. 5.4. 5.5. 5.6. 5.7. 5.8. 5.9. 5.10. 5.11. 5.12. 5.13. 5.14. 6.1. 6.2. 6.3. 6.4. 6.5. 6.6. 6.7. 7.1. 7.2. 7.3. 7.4. 7.5. 7.6. 7.7. 7.8. 8.1. 8.2. 8.3. 8.4. 8.5. 8.6. 8.7. 8.8. 8.9. 8.10. 8.11. 10.1. 10.2. 10.3. 10.4. 10.5. 10.6. 10.7. 10.8. 10.9. 10.10.
你也可以下载代码的.zip或者.tar文件,解压后在你的服务器上使用。
如果你愿意使用git,欢迎你复制或fork这个库。
查看更多关于什么时候判断运算结果为true 和什么时候判断运算结果为
false的资料。
你有的时候会看到开发者使用以下语句代替if进行流程控制
// 当foo的值为真的时候执行doSomething来处理foo
foo && doSomething(foo);
// 如果baz为真,则把baz的值赋给bar
// 否则bar的值为函数craetBar的返回值
var bar = baz || createBar();
这种风格的代码非常的简洁和优雅,但是同时,特别对于初学者而言,往往晦涩难懂。把它放在这里是希望当你在阅读到这类代码的时候可以读懂。但是如果你还不能够理解它的本质,且没有熟练掌握的话,我们不建议你使用此类代码
,即使我们在变量名 i前使用关键字var,这也并不意味着 i 变量的作用域在
循环体内。我们将在后面的章节讨论变量的作用域。
的方式改变时,它们通常不被考虑。
。 你可能在其它的 JavaScript 代码中看到过这两种方法的使用。
我们了解到函数是如何访问到改变的变量值we saw how functions have access to changing variable values. 这种行为同样存在于循环的函数定义中 -- The same sort of behavior exists with functions defined within loops -- 函数观察到变量在函数定义后的改变,产生5次点击警告。the
function "sees" the change in the variable's value even after the function
is defined, resulting in all clicks alerting 5.
以下是一些通用选择技术的例子
变量名以一个美元符号开始。不像在其它的语言中,在 JavaScript 中没有特定的指定美元符号 -- 而是使用其它字符 。我们在这里使用它是为了表明变量包含一个 jQuery 对象。这是惯例 -- 一种
-- 这仅仅是惯例,而不是强制性的。
一旦你保存了选择器,你就能在保存的变量中调用 jQuery 方法,就像在原来的选择器中调用一样。
只有当你指定一个选择器后,选择器才会从页面取回元素。如果你添加元素到页面延迟了,你必须重新选择或将它们添加到存储在变量中的选择器中。当 DOM 改变时被保存的选择器不会自动更新。
的代码简单描述了 jQuery 的尺寸功能;
若要获得有关jQuery尺寸方法完整的信息,请访问.
在遍历很长的文档时要小心 -- 完整的遍历有必要保留你的文档结构,除非你从服务端到客户端创建了完整应用,否则一些事将很难保证。一个或两个步骤的遍历是好的,但是当你从一个容器到另一个容器时需要避免遍历的发生。
去除行间和末尾的空白。
大量额外空白
// 返回 '大量额外空白'
在数组和对象上迭代。
$.each([ 'foo', 'bar', 'baz' ], function(idx, val) {
console.log('element ' + idx + 'is ' + val);
$.each({ foo : 'bar', baz : 'bim' }, function(k, v) {
console.log(k + ' : ' + v);
还有一个方法 $.fn.each,也可用于在一个选择的元素中进行迭代。
在数组中返回值索引,如果值不在数组中就为 -1 。
var myArray = [ 1, 2, 3, 5 ];
if ($.inArray(4, myArray) !== -1) {
console.log('found it!');
使用后面对象的属性改变第一个对象的属性。
var firstObject = { foo : 'bar', a : 'b' };
var secondObject = { foo : 'baz' };
var newObject = $.extend(firstObject, secondObject);
console.log(firstObject.foo); // 'baz'
console.log(newObject.foo);
如果你不打算改变任何对象你可传递 $.extend,作为第一个参数传递一个空对象。
var firstObject = { foo : 'bar', a : 'b' };
var secondObject = { foo : 'baz' };
var newObject = $.extend({}, firstObject, secondObject);
console.log(firstObject.foo); // 'bar'
console.log(newObject.foo);
返回一个函数它总是运行在一个提供的作用域里 — 就是说,this 的设置意味着内部传递函数到第二个参数。
var myFunction = function() { console.log(this); };
var myObject = { foo : 'bar' };
myFunction(); // 记录 window 对象
var myProxyFunction = $.proxy(myFunction, myObject);
myProxyFunction(); // 记录 myObject 对象
如果你拥有一个带方法的对象,你能传递对象和方法名去返回一个总运行在对象作用域里的函数。
var myObject = {
myFn : function() {
console.log(this);
$('#foo').click(myObject.myFn); // 记录 DOM 元素 #foo
$('#foo').click($.proxy(myObject, 'myFn')); // 记录 myObject
$.support 对象主要用于检测浏览器所支持的功能;在为不同浏览器定制 JavaScript 代码时它被推荐作为“future-proof”方法来使用。
虽然不赞成使用 $.browser 对象而鼓励使用 $.support 对象,但它仍保留在 jQuery 中而没删除。它提供了直接检测浏览器类型和版本的功能。
事件处理的函数可以接收事件对象为参数。
事件对象可以用来判断事件的类型以达到阻止该事件的默认动作的目的
想要获得关于事件对象的详细内容请访问。
可以很轻松完成颜色动画。我们将在书的后面章节讨论如何使用此插件。
details on properly formatting JSON, but as a general rule,
use built-in language methods for generating JSON on the
server to avoid syntax issues.
For transporting JSON data from another domain
For transporting data in a custom XML schema
I am a strong proponent of using the JSON format in most cases,
as it provides the most flexibility. It is especially useful for sending
both HTML and data at the same time.
here are several that you will use frequently:
Set to false if the request should be sent
synchronously. Defaults to true. Note that if you
set this option to false, your request will block execution of
other code until the response is received.
Whether to use a cached response if available. Defaults to
true for all dataTypes except "script" and "jsonp".
When set to false, the URL will simply have a cachebusting
parameter appended to it.
A callback function to run when the request is complete,
regardless of success or failure. The function receives the raw
request object and the text status of the request.
The scope in which the callback function(s) should run
(i.e. what this will mean inside the callback
function(s)). By default, this inside the callback
function(s) refers to the object originally passed to
The data to be sent to the server. This can either be an
object or a query string, such as
foo=bar&baz=bim.
The type of data you expect back from the server. By
default, jQuery will look at the MIME type of the response if no
dataType is specified.
A callback function to run if the request results in an
error. The function receives the raw request object and the text
status of the request.
The callback name to send in a query string when making a
JSONP request. Defaults to "callback".
A callback function to run if the request succeeds. The
function receives the response data (converted to a JavaScript
object if the dataType was JSON), as well as the text status of
the request and the raw request object.
The time in milliseconds to wait before considering the
request a failure.
traditional
Set to true to use the param serialization style in use
prior to jQuery 1.4. For details, see .
The type of the request, "POST" or "GET". Defaults to
"GET". Other request types, such as "PUT" and "DELETE" can be
used, but they may not be supported by all browsers.
The URL for the request.
The url option is the only required property of the
all other properties are
is a well-tested tool for adding Ajax capabilities to
forms, and you should generally use it for handling forms with Ajax rather
than trying to roll your own solution for anything remotely complex. That
said, there are a two jQuery methods you should know that relate to form
processing in jQuery: $.fn.serialize and
$.fn.serializeArray.
, which we'll use in the following example to fetch news
about cats.
选好插件之后就可以将它加入到页面中去了。先下载,需要解压就解压,
将插件脚本放在应用所在的目录中,再通过 script 标签(放置于 jQuery 之后)
将插件引入到页面中去。
。文中讲述了他开发的一个叫 $.fn.hilight 的插件,
用于对在有 metadata 插件时提供一些支持,和一个统一设置插件的全局和实例参数的方法。
(已获作者许可)
虽然大多数的 jQuery 插件都是无状态的(stateless),也就是说,
与插件进行交互的就限于调用插件时的那一组对象,
但是有好大一部分功能需求没办法通过这种简单的插件模式来实现。
为了填补这一空白,jQuery UI 实现一套更加先进的插件系统。
它可以管理状态,允许通过一个插件暴露多个函数,并提供多个扩展点。
这套系统被称为 widget factory,对应 jQuery.widget,
也是 jQuery UI 1.8 的一部分。不过,它是可以独立于 jQuery UI 使用的。
我们接下来创建一个简单的进度条插件,用来演示 widget factory 的能力。
我们首先创建一个只能设置一次的进度条。
下面是实现代码,使用 jQuery.widget 创建一个插件。
它接受两个参数,插件名字和带有具体实现方法的对象。
当插件被调用时,它会创建一个新的插件实例,而插件方法的执行对象也就是那个实例。
这与标准 jQuery 插件实现有两点是很不一样的。一是,执行者是对象而不是 DOM 元素;
二是,执行者永远是单个对象,而不是元素集。
并做出贡献!
并且多看多思考。
——一个功能单元应当以其特有的方式存在,功能单元之间的通信应当通过定制事件或pub/sub这样的消息系统进行处理。尽可能避免功能单元之间的直接通信。
松藕合的概念对于首次挑战复杂应用程序的开发人员可能尤为烦恼,因此当你正在入门时要格外关注。
,并且得到RequireJS作者James Burke的许可。
当项目达到一定规模时,管理项目的脚本模块开始变得非常棘手。你显然需要按正确的次序组织好这些脚本,并且开始认真考虑将脚本打包部署,只让一个或少数请求去载入这些脚本。你或许还想在页面加载完成后立即加载这些脚本代码。
When a project reaches a certain size, managing the script modules
for a project starts to get tricky. You need to be sure to sequence the
scripts in the right order, and you need to start seriously thinking about
combining scripts together into a bundle for deployment, so that only one
or a very small number of requests are made to load the scripts. You may
also want to load code on the fly, after page load.
RequireJS是James Burke设计的一个依赖管理工具,它可以帮助你管理脚本模块并以正确的次序加载脚本,不需要改变标记即可以通过RequireJS优化工具轻松组合后续的脚本。它提供一种简单的方式在页面加载完成后载入脚本,随着时间的推移可以有效扩充脚本文件的尺寸。
RequireJS的模块系统可以帮助你定义作用域良好的模块,即使你却不关注这套系统也能获得依赖管理和构建时优化的好处。如果你开始创建模块化的代码并在少数场合重用它们,久而久之,RequireJS的模块格式会使编写联机加载的封装代码十分简单。特别是你想使用国际化字符串,让你的项目针对不同语言进行本地化,或者加载HTML字符串并确保在执行代码前这些字符串确实有效,或者只是把JSONP服务当作依赖关系来使用,RequireJS都是你的得力伙伴。
。这个构建版本不包括RequireJS和jQuery功能发生重复的部分。你还会发现下载对你也很有帮助。
在jQuery中使用RequireJS
在页面中使用RequireJS相当简单:只需要引入内建RequireJS的jQuery和你的应用程序文件。下面的示例假设jQuery和你的其它脚本都位于scripts/目录。
Example 10.5. 使用RequireJS:一个简单示例
&!DOCTYPE html&
&title&jQuery+RequireJS Sample Page&/title&
&script src="scripts/require-jquery.js"&&/script&
&script&require(["app"]);&/script&
&h1&jQuery+RequireJS Sample Page&/h1&
调用require(["app"])是在告诉RequireJS加载scripts/app.js文件。RequireJS将从require-jquery.js所在的目录加载所有传入require()的依赖脚本,且不需要.js扩展名,不过也可以将它配置成另一种完全不同的工作方式。如果你乐意使用完整路径,还可以通过下面的方式来处理:
&script&require(["scripts/app.js"]);&/script&
app.js里有什么?有另一种方式可以调用require.js来加载你需要的脚本,在页面中随心所欲的进行初始化工作。这个示例中app.js脚本加载了两个插件:jquery.alpha.js和jquery.beta.js(不是什么真正的插件,只是随便举个例子)。这些插件需要放进和require-jquery.js相同的目录:
Example 10.6. 使用依赖的简单JavaScript文件
require(["jquery.alpha", "jquery.beta"], function() {
//jquery.alpha.js和jquery.beta.js插件已经加载。
$(function() {
$('body').alpha().beta();
通过RequireJS创建可重用的模块
通过require.def(),RequireJS让定义可重用的模块变得十分简单。RequireJS模块可以使用依赖来定义一个模块,并且Require模块可以返回一个值——不管是一个对象还是一个函数——并让其它模块来使用。
如果你的模块没有任何依赖性,只需要指定一个模块名称作为第一个参数调用require.def()。第二个参数只是一个定义了模块属性的对象原语。例如:
Example 10.7. 定义一个没有依赖性的RequireJS模块
require.def("my/simpleshirt",
color: "black",
size: "unisize"
这个示例将被放到my/simpleshirt.js文件中。
如果你的模块存在依赖性,你可以将依赖关系作为第二个参数传递给require.def()(用数组的方式),接着传递一个函数作为第三个参数。这个函数将在所有依赖关系加载完成后被调用,以便定义这个模块。
Example 10.8. 定义一个有依赖性的RequireJS模块
require.def("my/shirt",
["my/cart", "my/inventory"],
function(cart, inventory) {
//返回一个对象以便定义"my/shirt"模块。
color: "blue",
size: "large"
addToCart: function() {
inventory.decrement(this);
cart.add(this);
在这个例子里创建了my/shirt模块,它依赖于my/cart和my/inventory。在磁盘上,这些文件被构造成这样:
my/cart.js
my/inventory.js
my/shirt.js
定义my/shirt的函数在my/cart和my/inventory加载前不会被调用,函数以cart和inventory参数接收模块。函数参数的顺序必须和依赖关系数组中的依赖关系次序一致。调用函数后返回的对象定义了my/shirt模块。通过这种方式定义模块,my/shirt不会作为一个全局对象存在。在模块中定义全局变量被明确地阻止,所以同一时间可以在同一个页面使用多个不同版本的模块。
模块中返回对象不是必需的;允许从函数中返回任何有效值。
Example 10.9. 定义一个返回函数的RequireJS模块
require.def("my/title",
["my/dependency1", "my/dependency2"],
function(dep1, dep2) {
//返回一个函数以定义"my/title",该函数可返回或设置窗口标题。
return function(title) {
return title ? (window.title = title) : window.
每个JavaScript文件必须只有唯一的一个模块。
代码优化:RequireJS构建工具
一旦你结合RequireJS进行依赖管理,实施页面优化将会非常简单。下载RequireJS源文件并放到你喜欢的任何地方,最好是放到web开发以外的区域。因为这个例子的原因,RequireJS源文件被放到了webapp的同一级目录,它包括了HTML页面和包含所有脚本的目录。完整的目录结构如下:
requirejs/ (用于构建工具)
webapp/app.html
webapp/scripts/app.js
webapp/scripts/require-jquery.js
webapp/scripts/jquery.alpha.js
webapp/scripts/jquery.beta.js
接着,在这个拥有require-jquery.js和app.js的脚本目录里,创建叫作app.build.js的文件,并且具有下列内容:
Example 10.10. RequireJS构建配置文件
appDir: "../",
baseUrl: "scripts/",
dir: "../../webapp-build",
//如果你想通过闭包编译器用"simple"优化模式压缩代码,
//可以注释掉optimize这一行
optimize: "none",
modules: [
name: "app"
要使用这个构建工具,你需要安装Java 6。闭包编译器用于JavaScript压缩环节(如果optimize:
"none"被注释掉),它需要Java 6的支持。
要开始进行构建工作,需进入webapp/scripts目录,执行下列命令:
# 非Windows系统
../../requirejs/build/build.sh app.build.js
# Windows系统
..\..\requirejs\build\build.bat app.build.js
现在,webapp-build目录中将会生成app.js,jquery.alpha.js和jquery.beta.js这样几个文件。如果在浏览器中打开webapp-build目录中的app.html文件,你不会看到任何加载jquery.alpha.js和jquery.beta.js的网络请求。
创建Portlet模块
在你的浏览器中打开/exercises/portlets.html文件,使用/exercises/js/portlets.js文件,你的任务是使用模块模式编写一个portlet创建函数,就像下列代码那样工作:
var myPortlet = Portlet({
title : 'Curry',
source : 'data/html/curry.html',
initialState : 'open' // 或'closed'
myPortlet.$element.appendTo('body');
每个Portlet应该是一个DIV,带有一个标题、一个内容区域、一个打开/关闭按钮、一个删除portlet的按钮和一个刷新portlet的按钮。Portlet函数返回的portlet应该具有下列公有API:
myPortlet.open(); // 强制打开状态
myPortlet.close(); // 强制关闭状态
myPortlet.toggle(); // 切换开/关状态
myPortlet.refresh(); // 刷新内容
myPortlet.destroy(); // 从页面中移除一个portlet
myPortlet.setSource('data/html/onions.html'); // 改变数据源
Chapter 11. Custom Events
Introducing Custom Events
We’re all familiar with the basic events — click, mouseover, focus,
blur, submit, etc. — that we can latch on to as a user interacts with the
browser. Custom events open up a whole new world of event-driven
programming. In this chapter, we’ll use jQuery’s custom events system to
make a simple Twitter search application.
It can be difficult at first to understand why you'd want to use
custom events, when the built-in events seem to suit your needs just fine.
It turns out that custom events offer a whole new way of thinking about
event-driven JavaScript. Instead of focusing on the element that triggers
an action, custom events put the spotlight on the element being acted
upon. This brings a bevy of benefits, including:
Behaviors of the target element can easily be triggered by
different elements using the same code.
Behaviors can be triggered across multiple, similar, target
elements at once.
Behaviors are more clearly associated with the target element in
code, making code easier to read and maintain.
Why should you care? An example is probably the best way to explain.
Suppose you have a lightbulb in a room in a house. The lightbulb is
currently turned on, and it’s controlled by two three-way switches and a
&div class="room" id="kitchen"&
&div class="lightbulb on"&&/div&
&div class="switch"&&/div&
&div class="switch"&&/div&
&div class="clapper"&&/div&
Triggering the clapper or either of the switches will change the
state of the lightbulb. The switches and the clapper don’t care what state
they just want to change the state.
Without custom events, you might write some code like this:
$('.switch, .clapper').click(function() {
var $light = $(this).parent().find('.lightbulb');
if ($light.hasClass('on')) {
$light.removeClass('on').addClass('off');
$light.removeClass('off').addClass('on');
With custom events, your code might look more like this:
$('.lightbulb').bind('changeState', function(e) {
var $light = $(this);
if ($light.hasClass('on')) {
$light.removeClass('on').addClass('off');
$light.removeClass('off').addClass('on');
$('.switch, .clapper').click(function() {
$(this).parent().find('.lightbulb').trigger('changeState');
This last bit of code is not that exciting, but something important
has happened: we’ve moved the behavior of the lightbulb to the lightbulb,
and away from the switches and the clapper.
Let’s make our example a little more interesting. We’ll add another
room to our house, along with a master switch, as shown here:
&div class="room" id="kitchen"&
&div class="lightbulb on"&&/div&
&div class="switch"&&/div&
&div class="switch"&&/div&
&div class="clapper"&&/div&
&div class="room" id="bedroom"&
&div class="lightbulb on"&&/div&
&div class="switch"&&/div&
&div class="switch"&&/div&
&div class="clapper"&&/div&
&div id="master_switch"&&/div&
If there are any lights on in the house, we want the master switch
to tur otherwise, we want it to turn all lights on.
To accomplish this, we’ll add two more custom events to the lightbulbs:
turnOn and turnOff. We’ll make use of them in
the changeState custom event, and use some logic to decide
which one the master switch should trigger:
$('.lightbulb')
.bind('changeState', function(e) {
var $light = $(this);
if ($light.hasClass('on')) {
$light.trigger('turnOff');
$light.trigger('turnOn');
.bind('turnOn', function(e) {
$(this).removeClass('off').addClass('on');
.bind('turnOff', function(e) {
$(this).removeClass('off').addClass('on');
$('.switch, .clapper').click(function() {
$(this).parent().find('.lightbulb').trigger('changeState');
$('#master_switch').click(function() {
if ($('.lightbulb.on').length) {
$('.lightbulb').trigger('turnOff');
$('.lightbulb').trigger('turnOn');
Note how the behavior of the master switch is attached to the master
the behavior of a lightbulb belongs to the lightbulbs.
If you’re accustomed to object-oriented programming, you may find
it useful to think of custom events as methods of objects. Loosely
speaking, the object to which the method belongs is created via the
jQuery selector. Binding the changeState custom event to all
$(‘.light’) elements is akin to having a class called
Light with a method of changeState, and then
instantiating new Light objects for each element with a
classname of light.
Here is an example of the usage of $.fn.bind and
$.fn.trigger that uses custom data in both cases:
$(document).bind('myCustomEvent', { foo : 'bar' }, function(e, arg1, arg2) {
console.log(e.data.foo); // 'bar'
console.log(arg1); // 'bim'
console.log(arg2); // 'baz'
$(document).trigger('myCustomEvent', [ 'bim', 'baz' ]);
A Sample Application
To demonstrate the power of custom events, we’re going to create a
simple tool for searching Twitter. The tool will offer several ways for
a user to add search terms to the display: by entering a search term in
a text box, by entering multiple search terms in the URL, and by
querying Twitter for trending terms.
The results for each term will be shown in
these containers will be able to be expanded, collapsed, refreshed, and
removed, either individually or all at once.
When we’re done, it will look like this:
Figure 11.1. Our finished application
We’ll start with some basic HTML:
&h1&Twitter Search&/h1&
&input type="button" id="get_trends"
value="Load Trending Terms" /&
&input type="text" class="input_text"
id="search_term" /&
&input type="submit" class="input_submit"
value="Add Search Term" /&
&div id="twitter"&
&div class="template results"&
&h2&Search Results for
&span class="search_term"&&/span&&/h2&
This gives us a container (#twitter) for our widget, a template
for our results containers (hidden via CSS), and a simple form where
users can input a search term. (For the sake of simplicity, we’re
going to assume that our application is JavaScript-only and that our
users will always have CSS.)
There are two types of objects we’ll want to act on: the results
containers, and the Twitter container.
The results containers are the heart of the application. We’ll
create a plugin that will prepare each results container once it’s
added to the Twitter container. Among other things, it will bind the
custom events for each container and add the action buttons at the top
right of each container. Each results container will have the
following custom events:
Mark the container as being in the “refreshing” state, and
fire the request to fetch the data for the search term.
Receive the returned JSON data and use it to populate the
container.
Remove the container from the page after the user verifies
the request to do so. Verification can be bypassed by passing
true as the second argument to the event handler. The remove
event also removes the term associated with the results
container from the global object containing the search
Add a class of collapsed to the container, which will hide
the results via CSS. It will also turn the container’s
“Collapse” button into an “Expand” button.
Remove the collapsed class from the container. It will
also turn the container’s “Expand” button into a “Collapse”
The plugin is also responsible for adding the action buttons to
the container. It binds a click event to each action’s list item, and
uses the list item’s class to determine which custom event will be
triggered on the corresponding results container.
$.fn.twitterResult = function(settings) {
return this.each(function() {
var $results = $(this),
$actions = $.fn.twitterResult.actions =
$.fn.twitterResult.actions ||
$.fn.twitterResult.createActions(),
$a = $actions.clone().prependTo($results),
term = settings.
$results.find('span.search_term').text(term);
['refresh', 'populate', 'remove', 'collapse', 'expand'],
function(i, ev) {
$results.bind(
{ term : term },
$.fn.twitterResult.events[ev]
// use the class of each action to figure out
// which event it will trigger on the results panel
$a.find('li').click(function() {
// pass the li that was clicked to the function
// so it can be manipulated if needed
$results.trigger($(this).attr('class'), [ $(this) ]);
$.fn.twitterResult.createActions = function() {
return $('&ul class="actions" /&').append(
'&li class="refresh"&Refresh&/li&' +
'&li class="remove"&Remove&/li&' +
'&li class="collapse"&Collapse&/li&'
$.fn.twitterResult.events = {
refresh : function(e) {
// indicate that the results are refreshing
var $this = $(this).addClass('refreshing');
$this.find('p.tweet').remove();
$results.append('&p class="loading"&Loading ...&/p&');
// get the twitter data using jsonp
$.getJSON(
'/search.json?q=' +
escape(e.data.term) + '&rpp=5&callback=?',
function(json) {
$this.trigger('populate', [ json ]);
populate : function(e, json) {
var results = json.
var $this = $(this);
$this.find('p.loading').remove();
$.each(results, function(i,result) {
var tweet = '&p class="tweet"&' +
'&a href="/' +
result.from_user +
result.from_user +
'&/a&: ' +
result.text +
' &span class="date"&' +
result.created_at +
'&/span&' +
$this.append(tweet);
// indicate that the results
// are done refreshing
$this.removeClass('refreshing');
remove : function(e, force) {
!confirm('Remove panel for term ' + e.data.term + '?')
$(this).remove();
// indicate that we no longer
// have a panel for the term
search_terms[e.data.term] = 0;
collapse : function(e) {
$(this).find('li.collapse').removeClass('collapse')
.addClass('expand').text('Expand');
$(this).addClass('collapsed');
expand : function(e) {
$(this).find('li.expand').removeClass('expand')
.addClass('collapse').text('Collapse');
$(this).removeClass('collapsed');
The Twitter container itself will have just two custom events:
getResults
Receives a search term and checks to determine whether
there’s already a results co if not, adds a
results container using the results template, set up the results
container using the $.fn.twitterResult plugin
discussed above, and then triggers the refresh
event on the results container in order to actually load the
results. Finally, it will store the search term so the
application knows not to re-fetch the term.
Queries Twitter for the top 10 trending terms, then
iterates over them and triggers the getResults
event for each of them, thereby adding a results container for
each term.
Here's how the Twitter container bindings look:
$('#twitter')
.bind('getResults', function(e, term) {
// make sure we don't have a box for this term already
if (!search_terms[term]) {
var $this = $(this);
var $template = $this.find('div.template');
// make a copy of the template div
// and insert it as the first results box
$results = $template.clone().
removeClass('template').
insertBefore($this.find('div:first')).
twitterResult({
'term' : term
// load the content using the "refresh"
// custom event that we bound to the results container
$results.trigger('refresh');
search_terms[term] = 1;
.bind('getTrends', function(e) {
var $this = $(this);
$.getJSON('/trends.json?callback=?', function(json) {
var trends = json.
$.each(trends, function(i, trend) {
$this.trigger('getResults', [ trend.name ]);
So far, we’ve written a lot of code that does approximately
nothing, but that’s OK. By specifying all the behaviors that we want
our core objects to have, we’ve created a solid framework for rapidly
building out the interface.
Let’s start by hooking up our text input and the “Load Trending
Terms” button. For the text input, we’ll capture the term that was
entered in the input and pass it as we trigger the Twitter container’s
getResults event. Clicking the “Load Trending Terms” will
trigger the Twitter container’s getTrends event:
$('form').submit(function(e) {
e.preventDefault();
var term = $('#search_term').val();
$('#twitter').trigger('getResults', [ term ]);
$('#get_trends').click(function() {
$('#twitter').trigger('getTrends');
By adding a few buttons with the appropriate IDs, we can make it
possible to remove, collapse, expand, and refresh all results
containers at once, as shown below. For the remove button, note how
we’re passing a value of true to the event handler as its second
argument, telling the event handler that we don’t want to verify the
removal of individual containers.
$.each(['refresh', 'expand', 'collapse'], function(i, ev) {
$('#' + ev).click(function(e) { $('#twitter div.results').trigger(ev); });
$('#remove').click(function(e) {
if (confirm('Remove all results?')) {
$('#twitter div.results').trigger('remove', [ true ]);
Conclusion
Custom events offer a new way of thinking about your code: they
put the emphasis on the target of a behavior, not on the element that
triggers it. If you take the time at the outset to spell out the
pieces of your application, as well as the behaviors those pieces need
to exhibit, custom events can provide a powerful way for you to “talk”
to those pieces, either one at a time or en masse. Once the behaviors
of a piece have been described, it becomes trivial to trigger those
behaviors from anywhere, allowing for rapid creation of and
experimentation with interface options. Finally, custom events can
enhance code readability and maintainability, by making clear the
relationship between an element and its behaviors.
You can see the full application at
demos/custom-events.html and
demos/js/custom-events.js in the sample}

我要回帖

更多关于 bootstrap alert.js 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信