先看bootstrap.typehead.js的结构

var Typeahead = function ( element, options ){} //构造器
Typeahead.prototype = {} //构造器的原型
$.fn.typeahead = function ( option ){} //jQuery原型上自定义方法
$.fn.typeahead.defaults ={} //默认参数
$.fn.typeahead.Constructor = Typeahead //重写jQuery原型上的自定义方法的构造器名
$(function () {}) //初始化

HTML结构

<input class="span3" type="text"
data-source="['Alabama','Alaska','Arizona','Arkansas','California','Colorado','Connecticut','Delaware','Florida'
,'Georgia','Hawaii','Idaho','Illinois','Indiana','Iowa','Kansas','Kentucky','Louisiana','Maine','Maryland'
,'Massachusetts','Michigan','Minnesota','Mississippi','Missouri','Montana','Nebraska','Nevada','New Hampshire'
,'New Jersey','New Mexico','New York','North Dakota','North Carolina','Ohio','Oklahoma','Oregon','Pennsylvania'
,'Rhode Island','South Carolina','South Dakota','Tennessee','Texas','Utah','Vermont','Virginia','Washington'
,'West Virginia','Wisconsin','Wyoming']" data-items="4" data-provide="typeahead" style="margin: 0 auto;"/>

先从初始化开始

/*
* 初始化
* */
$(function () {
$('body').on('focus.typeahead.data-api', '[data-provide="typeahead"]', function (e) {
var $this = $(this)
if ($this.data('typeahead')) return
e.preventDefault() //阻止冒泡
$this.typeahead($this.data())
})
})

为所有拥有data-provide='typehead'属性的标签绑定focus事件,并且阻止事件冒泡,进入jQuery的原型方法中

/*
* jQuery原型上自定义方法
* */
$.fn.typeahead = function ( option ) {
return this.each(function () {
var $this = $(this)
, data = $this.data('typeahead')
, options = typeof option == 'object' && option
if (!data) $this.data('typeahead', (data = new Typeahead(this, options)))//实例化构造器
if (typeof option == 'string') data[option]()
})
}

由于,$this.data('typehead')为空,我们执行实例化。

/*
* 构造器
* */
var Typeahead = function ( element, options ) {
this.$element = $(element)
this.options = $.extend({}, $.fn.typeahead.defaults, options)
this.matcher = this.options.matcher || this.matcher//原型上的matcher方法
this.sorter = this.options.sorter || this.sorter//原型上的sorter方法
this.highlighter = this.options.highlighter || this.highlighter//原型上的highlighter方法
this.$menu = $(this.options.menu).appendTo('body')//将下拉框ul加入body中,返回ul的jQuery对象
this.source = this.options.source //获得input控件里的参数。input优先级大于默认项
this.shown = false
this.listen()
}

这里注意一点是,控件中的data属性与默认项中如果有重名属性的话,data属性优先级高,会覆盖。进入listen方法

listen: function () {
this.$element
.on('blur', $.proxy(this.blur, this))//绑定blur事件
.on('keypress', $.proxy(this.keypress, this))//绑定keypress事件
.on('keyup', $.proxy(this.keyup, this))//绑定keyup事件
/*
* 如果浏览器内核是webkit或者是ie内核的,绑定keydown事件。
* */
if ($.browser.webkit || $.browser.msie) {
this.$element.on('keydown', $.proxy(this.keypress, this))
}
/*
* ul绑定click事件和mouserenter事件
* */
this.$menu
.on('click', $.proxy(this.click, this))
.on('mouseenter', 'li', $.proxy(this.mouseenter, this))
}

完成事件监听的绑定工作,至此初始化工作完成。原型上拥有一堆API,让我们一一尝试。

先看input的keypress事件,对应的keypress方法

keypress: function (e) {
if (!this.shown) return switch(e.keyCode) {
case 9: // tab
case 13: // enter
case 27: // escape
e.preventDefault()
break case 38: // up arrow
e.preventDefault()
this.prev()
break case 40: // down arrow
e.preventDefault()
this.next()
break
} e.stopPropagation() //阻止冒泡

键盘上的按钮对应响应的keyCode,preventDefault方法将阻止元素放生默认行为。如果按了向上的箭头,进入prev方法

prev: function (event) {
var active = this.$menu.find('.active').removeClass('active')
, prev = active.prev() if (!prev.length) {
prev = this.$menu.find('li').last()
} prev.addClass('active')
}

ul中li元素遍历,上箭头可以向上选择li元素,如果到顶了,则返回最下面的li元素重新开始。被选中的li元素会拥有active类,一个选中样式,其他li则没有。

next: function (event) {
var active = this.$menu.find('.active').removeClass('active')
, next = active.next() if (!next.length) {
next = $(this.$menu.find('li')[0])
} next.addClass('active')
}

next的方法与prev类似,像API中还有类似的方法,大家依照demo,一调试就可以出来,比如mouseenter,click,blur,show,hide方法等。

对于具有联想功能的插件,学习学习它的联想功能如何实现比较重要。

好,我们从keyup开始

keyup: function (e) {
switch(e.keyCode) {
case 40: // down arrow
case 38: // up arrow
break case 9: // tab
case 13: // enter
if (!this.shown) return
this.select()
break case 27: // escape
if (!this.shown) return
this.hide()
break default:
this.lookup()// 一般按键
} e.stopPropagation()
e.preventDefault()
}

如果我们输入一般字母,进入默认的lookup方法

 /*
* 查询匹配方法
* */
, lookup: function (event) {
var that = this
, items
, q this.query = this.$element.val()//获取用户输入内容
if (!this.query) { //不输入空格
return this.shown ? this.hide() : this
} items = $.grep(this.source, function (item) {
if (that.matcher(item)) return item
})//遍历this.source,其中的成员执行函数,最后返回结果
items = this.sorter(items)
if (!items.length) {
return this.shown ? this.hide() : this
}
/*截取前4位*/
return this.render(items.slice(0, this.options.items)).show()
}

这里代码有个错误,就是这个this.source,它的类型不是object,或者是一个数组,导致最后联想功能只能匹配一个字符串,现在的this.source只是字符串,所以我们需要让它变成object对象,有人用json的API,可以,浏览器不兼容怎么办,引入J相关JSON的兼容包就可以搞定了,那还有了,对,eval。这个方法缺点一大堆,不过简单粗暴直接。我们修改一下源码

items = $.grep(eval(this.source), function (item) {
if (that.matcher(item)) return item
})

其实解决办法很多,我这里图方便了,我们继续。修改return

return this.render(items).show();

进入render方法

/*
* 生成li标签
* */
, render: function (items) {
var that = this
items = $(items).map(function (i, item) {
i = $(that.options.item).attr('data-value', item) //往li中塞值
i.find('a').html(that.highlighter(item))
return i[0]
})
items.first().addClass('active') //默认下拉内容中第一个显示
this.$menu.html(items) //将生气li标签插入ul中
return this
}

看一下highlighter函数

highlighter: function (item) {
return item.replace(new RegExp('(' + this.query + ')', 'ig'), function ($1, match) {
return '<strong>' + match + '</strong>'
})
}

高亮处理,replace的用法,大家可以学习一下。

最后是show出来

/*
* 显示
* */
, show: function () {
var pos = $.extend({}, this.$element.offset(), {
height: this.$element[0].offsetHeight
}) this.$menu.css({
top: pos.top + pos.height
, left: pos.left
}) this.$menu.show()
this.shown = true
return this
}

调用jQuery的show方法显示。

这个插件中也有不少写的很蛋疼的方法,不过稍作修改就可以完成了,其实关于搜索这块的效率,我没有提及。每个人思路不一样,实现也不一样。希望园友们也能思考一下,能给出更加高效的查询办法。

内容不多,时间刚好,以上是我的一点读码体会,如有错误,请指出,大家共通学习。

bootstrap插件学习-bootstrap.typehead.js的更多相关文章

  1. bootstrap插件学习-bootstrap.dropdown.js

    bootstrap插件学习-bootstrap.dropdown.js 先看bootstrap.dropdown.js的结构 var toggle = '[data-toggle="drop ...

  2. bootstrap插件学习-bootstrap.modal.js

    bootstrap插件学习-bootstrap.modal.js 先从bootstrap.modal.js的结构看起. function($){ var Modal = function(){} // ...

  3. bootstrap插件学习-bootstrap.carousel.js

    先看bootstrap.carousel.js的结构 var Carousel = function (element, options){} //构造器 Carousel.prototype = { ...

  4. bootstrap插件学习-bootstrap.collapse.js

    先看bootstrap.collapse.js的结构 var Collapse = function ( element, options ){} // 构造器 Collapse.prototype ...

  5. bootstrap插件学习-bootstrap.alert.js

    我们先看bootstrap.alert.js的结构 var dismiss = '[data-dismiss="alert"]' //自定义属性 Alert = function ...

  6. bootstrap插件学习-bootstrap.button.js

    先看bootstrap.button.js的结构 var Button = function ( element, options ){} //构造器 Button.prototype = {} // ...

  7. bootstrap插件学习-bootstrap.popover.js

    先看bootstrap.popover.js的结构 var Popover = function ( element, options ){} //构造器 Popover.prototype = {} ...

  8. bootstrap插件学习-bootstrap.tooltip.js

    先看bootstrap-tooltip.js的结构 var Tooltip = function ( element, options ){} // 构造器 Tooltip.prototype ={} ...

  9. bootstrap插件学习-bootstrap.scrollspy.js

    先看bootstrap.dropdown.js的结构 function ScrollSpy(){} //构造函数 ScrollSpy.prototype = {} //构造器的原型 $.fn.scro ...

随机推荐

  1. bzoj 1191: [HNOI2006]超级英雄Hero

    1191: [HNOI2006]超级英雄Hero Time Limit: 10 Sec  Memory Limit: 162 MB 二分图匹配... Description 现在电视台有一种节目叫做超 ...

  2. [推荐]dubbo分布式服务框架知识介绍

    [推荐]dubbo分布式服务框架知识介绍 CentOS+Jdk+Jboss+dubbo+zookeeper集群配置教程    http://wenku.baidu.com/view/20e8f36bf ...

  3. 一道SQL面试例题 if...else 与聚集函数

    晚上回来,同学说面试遇到了一个SQL面试题目,自己做了一下,总结总结. 题目如下: 下面是产品数据表(产品id,颜色col,数量num),其中每种产品有1~2种颜色. 求每种产品各颜色的数量差值(对于 ...

  4. The main difference between Java & C++(转载)

    转载自:http://stackoverflow.com/questions/9192309/the-main-difference-between-java-c C++ supports point ...

  5. Revit中绘制带坡度管道

    激活管道绘制命令出现绘制管道上下文菜单,可以根据需要设置管道坡度值,是向上坡度还是向下坡度,其中两个命令非常有用,一个是继承高程,一个是忽略坡度以连接.在Revit建模中尝尝碰到一些带有坡度的管道,比 ...

  6. 神舟K650c i7(W350STQ)上成功装好Mac OS X 10.9,兼谈如何安装WinXP、7、8.1、OSX、Ubuntu五系统(Chameleon、MBR)

    作者:zyl910 参考教程——http://bbs.pcbeta.com/viewthread-1432534-1-4.html笔记本SNB和IVY平台Win7/Win8/Win8.1安装OS X ...

  7. 记录一下,如何配置nodejs nginx的反向代理

    本文是在mac下配置nodejs 在nginx下的反向代理 1.安装nodejs,之前就安装了. 2.安装nginx ,我采用的直接源码安装 3.进入 /usr/local/nginx/conf 目录 ...

  8. http协议读书笔记2-连接管理

    一.http是如何使用tcp连接的? http连接本质就是tcp连接和一些使用连接的规则.所有的http通讯都是由tcp/ip来承载的.tcp/ip是全球计算机及网络设备都在使用的一种常用的分组交换的 ...

  9. 【终极解决方案】为应用程序池“XXX”提供服务的进程在与 Windows Process Activation Service 通信时出现严重错误。该进程 ID 为“XXXX”。数据字段包含错误号。

    困扰我大半年的错误,今天偶然间被解决了,特此分享给被同样问题纠结的朋友们! 之前的求助帖,无人应答: http://www.cnblogs.com/freeton/archive/2012/08/28 ...

  10. SQL SERVER2012中使用游标来备份数据库

    在SQL SERVER中,添加JOB,可以使用以下语句设置定期备份数据库. DECLARE @name VARCHAR(50)--databasename DECLARE @path VARCHAR( ...