先看bootstrap-tooltip.js的结构

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

因为tooltip插件的使用比较多,调用者比较杂,源码中没有给出初始化的步骤,在看源码的过程中,我们手动添加初始化。

<p class="muted">
“这是我的第一次英文访问,很抱歉它不够严谨,但是我不得不这么做,不只因为采访时间限制,更因为我面对的是卡梅隆,这个人喜爱挑战、从无畏惧,他也希望别人如此,他可以原谅不完美,但他无法接受一个人不去努力接近自己的极限。” ——
<a rel="tooltip" href="#" data-original-title="柴静始终站在离新闻最近的地方,她以她的犀利和敏锐、坚定与坚持,最终历练成为一名优秀的新闻工作者。 ">柴静</a>
《看见》专访
<a id="a1" rel="tooltip" href="#" data-original-title="1954年8月16日生于加拿大的著名电影导演,擅长拍摄动作片以及科幻电影。">卡梅隆</a>
</p>
$("#a1").tooltip();

在script标签部分加入以上代码,我们可以鼠标移入'卡梅隆'时显示提示框了。

下面开始,进入jQuery原型上的自定义方法tooltip中

/*
* jQuery原型上自定义的方法
* */
$.fn.tooltip = function ( option ) {
return this.each(function () {
var $this = $(this)
, data = $this.data('tooltip')
, options = typeof option == 'object' && option
if (!data) $this.data('tooltip', (data = new Tooltip(this, options)))//实例化构造器
if (typeof option == 'string') data[option]()//支持传入方法名参数,执行该方法。
})
}

跟之前的几个插件类似,进入构造器中。

/*
* 构造器
* */
var Tooltip = function ( element, options ) {
this.init('tooltip', element, options)//实例化直接调用原型的init方法
}

进入原型上的init方法

init: function ( type, element, options ) {
var eventIn
, eventOut this.type = type
this.$element = $(element)
this.options = this.getOptions(options)
this.enabled = true if (this.options.trigger != 'manual') { //选择事件名
eventIn = this.options.trigger == 'hover' ? 'mouseenter' : 'focus'
eventOut = this.options.trigger == 'hover' ? 'mouseleave' : 'blur'
//绑定事件 this.$element.on(eventIn, this.options.selector, $.proxy(this.enter, this))//其中有false,达到阻止冒泡的功能
this.$element.on(eventOut, this.options.selector, $.proxy(this.leave, this))
} this.options.selector ?
(this._options = $.extend({}, this.options, { trigger: 'manual', selector: '' })) :
this.fixTitle()//没有默认参数执行
}

init方法一般执行初始化的步骤,其中的getOptions方法

/*
* 添加默认项
* */
, getOptions: function ( options ) {
options = $.extend({}, $.fn[this.type].defaults, options, this.$element.data())
if (options.delay && typeof options.delay == 'number') {
options.delay = {
show: options.delay
, hide: options.delay
}
} return options
}

这里我们看到init方法为点击标签绑定了两种事件mouseenter和mouseleave,它们与mouseover和mouseout的区别:

不论鼠标指针穿过被选元素或其子元素,都会触发 mouseover 事件。

只有在鼠标指针穿过被选元素时,才会触发 mouseenter 事件。

绑定完事件之后,如果是无参数时,我们执行fixTitle方法

/*
* 将被点击标签的title属性值转给data-original-title属性,最后删除title属性
* */
, fixTitle: function () {
var $e = this.$element
if ($e.attr('title') || typeof($e.attr('data-original-title')) != 'string') {
$e.attr('data-original-title', $e.attr('title') || '').removeAttr('title')
}
}

为data-original-title属性赋值,为以后将该值加如提示框中做准备。

当鼠标移入时,触发mouseenter事件,进入绑定好的enter方法中

/*
* 目的调用show方法
* */
, enter: function ( e ) {
/*
* 以下方法执行了jQuery原型上的tooltip方法。通过each遍历,获取data对象中的tooltip属性:即该对象的jQuery对象
* 感觉这个写法蛋疼
* */
var self = $(e.currentTarget)[this.type](this._options).data(this.type)//e.currentTarget获取当前点击对象 if (!self.options.delay || !self.options.delay.show) {
self.show()//鼠标移上去执行show方法
} else {
self.hoverState = 'in'
setTimeout(function() {
if (self.hoverState == 'in') {
self.show()
}
}, self.options.delay.show)
}
}

纵观这个方法,其主要目的是为了调用show方法。

/*
* 显示提示框
* */
, show: function () {
var $tip
, inside
, pos
, actualWidth
, actualHeight
, placement
, tp if (this.hasContent() && this.enabled) {
$tip = this.tip()//获取提示框的jQuery对象
this.setContent()//给提示框赋值,初始化提示框的样式 if (this.options.animation) {
$tip.addClass('fade')//提示框拥有运动效果,加入fade类
} placement = typeof this.options.placement == 'function' ?
this.options.placement.call(this, $tip[0], this.$element[0]) :
this.options.placement//控制提示框的显示方位,默认为top inside = /in/.test(placement)//是否是in $tip
.remove()
.css({ top: 0, left: 0, display: 'block' })
.appendTo(inside ? this.$element : document.body)
/*先将提示框从文档中删除,获取其返回对象,即本身,加入样式,最后再重新插回文档中,这么写主要考虑in的情况
* 符合一种操作规范,如果添加样式,操作dom过于复杂,可以先将节点从dom中取出,经过一系列装饰后,再加入dom中,第一
* 便于浏览器渲染,二来也符合dom操作规范
* */
pos = this.getPosition(inside)//获取被点击对象的位置和本身尺寸
//获取提示框的宽度和高度
actualWidth = $tip[0].offsetWidth
actualHeight = $tip[0].offsetHeight
//我们拿top举例,在a标签上方,left方向,对着a标签居中。
switch (inside ? placement.split(' ')[1] : placement) {
case 'bottom':
tp = {top: pos.top + pos.height, left: pos.left + pos.width / 2 - actualWidth / 2}
break
case 'top':
tp = {top: pos.top - actualHeight, left: pos.left + pos.width / 2 - actualWidth / 2}
break
case 'left':
tp = {top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left - actualWidth}
break
case 'right':
tp = {top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left + pos.width}
break
} $tip
.css(tp)
.addClass(placement)//配合内部的div实现小三角效果
.addClass('in')//半透明效果
}
}

show方法是这个插件的核心方法,与show相关的几个方法,tip()方法,获得提示框模版,setContent()为提示框赋值,hasContent()中调用getTitle()方法获取被点击标签的获取data-original-title属性的值。逻辑不复杂,插件相关的方法调用比较多,耐心点看。

/*
* 调用getTitle方法
* */
, hasContent: function () {
return this.getTitle()
}
/*
* 获取data-original-title属性的值
* */
, getTitle: function () {
var title
, $e = this.$element
, o = this.options title = $e.attr('data-original-title')
|| (typeof o.title == 'function' ? o.title.call($e[0]) : o.title)
title = (title || '').toString().replace(/(^\s*|\s*$)/, "")//将title中的|去除,并且将|两边的文字合并 return title
}

tip方法

/*
* 返回提示框模版的jQuery对象
* */
, tip: function () {
return this.$tip = this.$tip || $(this.options.template)
}

为提示框赋内容

/*
* 往提示框中添加title信息,初始化提示框的样式
* */
, setContent: function () {
var $tip = this.tip()
$tip.find('.tooltip-inner').html(this.getTitle())//添加内容信息
$tip.removeClass('fade in top bottom left right')
}

调用getPosition方法,获得对象的位置和尺寸

/*
* 获取对象的高度和宽度,和偏移值(left和top)
* */
, getPosition: function (inside) {
return $.extend({}, (inside ? {top: 0, left: 0} : this.$element.offset()), {
width: this.$element[0].offsetWidth
, height: this.$element[0].offsetHeight
})
}

offsetWidth和offsetHeight是javascript元素的属性。表示内容高度+内边距+边框,内容宽度+内边距+边框。

对于提示框的显示,默认在被点击标签的上方。相对于被点击标签居中。

当鼠标移开时,触发原型上的leave方法

/*
* 调用hide方法
* */
, leave: function ( e ) {
/*
* 与enter中一样
* */
var self = $(e.currentTarget)[this.type](this._options).data(this.type) if (!self.options.delay || !self.options.delay.hide) {
self.hide()
} else {
self.hoverState = 'out'
setTimeout(function() {
if (self.hoverState == 'out') {
self.hide()
}
}, self.options.delay.hide)
}
}

进入核心方法hide

hide: function () {
var that = this
, $tip = this.tip() $tip.removeClass('in')
/*
* 定义了提示框消失的特效,要显示这个特效,需要引入其他js,这先不讨论
* */
function removeWithAnimation() {
var timeout = setTimeout(function () {
$tip.off($.support.transition.end).remove()
}, 500) $tip.one($.support.transition.end, function () {
clearTimeout(timeout)
$tip.remove()
})
} $.support.transition && this.$tip.hasClass('fade') ?
removeWithAnimation() :
$tip.remove()//直接删除提示框
}

我们没有引入相关js时,提示框直接删除了。

有兴趣的朋友可以研究一下bootstrap.tooltip插件对于提示框样式的编写,也挺不错的。最后插件还提供了几个方法,便于我们以后扩展。

/*
* 开启提示框功能
* */
, enable: function () {
this.enabled = true
} /*
* 禁用提示框功能
* */
, disable: function () {
this.enabled = false
}
/*开启/禁用切换*/
, toggleEnabled: function () {
this.enabled = !this.enabled
}
/*提示框显示隐藏切换*/
, toggle: function () {
this[this.tip().hasClass('in') ? 'hide' : 'show']()
} validate: function () {
if (!this.$element[0].parentNode) {
this.hide()
this.$element = null
this.options = null
}
}

使用的时候,直接用jQuery取得一个dom对象点就能点出上述的方法了,很方便。

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

bootstrap插件学习-bootstrap.tooltip.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.popover.js

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

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

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

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

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

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

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

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

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

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

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

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

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

随机推荐

  1. 如何提交docker镜像到DockerHub

    Write a Dockerfile In detail: FROM(指定基础image) 构建指令,必须指定且需要在Dockerfile其他指令的前面.后续的指令都依赖于该指令指定的image.FR ...

  2. Hibernate入门6.Hibernate检索方式

    Hibernate入门6.Hibernate检索方式 20131128 代码下载 链接: http://pan.baidu.com/s/1Ccuup 密码: vqlv Hibernate的整体框架已经 ...

  3. SQL Server 内存中OLTP内部机制概述(四)

    ----------------------------我是分割线------------------------------- 本文翻译自微软白皮书<SQL Server In-Memory ...

  4. Android视觉规范-间距规范与文字规范单位换算(dip、sp与px)

    http://blog.csdn.net/shimiso/article/details/29826073 1.dip与px Android工程师在写页面时,margin值的单位是dip,而视觉设计师 ...

  5. 大型架构.net平台篇(WEB层均衡负载nginx)

    第一部分 WEB层均衡负载.net平台下,我目前部署过的均衡负载有两种方式(iis7和Nginx),以下以Nginx为例讲解web层的均衡负载. 简介:Nginx 超越 Apache 的高性能和稳定性 ...

  6. Visual Studio 2013 and .NET 4.6

    I'm trying to set the 4.6 .NET framework for my project and in the settings, as it wasn't listed, I ...

  7. JavaScript 中数组实用浅析

    本文适用于HTML.ASP 中的 JavaScript 脚本代码.代码以 HTML 中的 JS 为例,如果在 ASP 中,请将 document.write 改为 Response.Write 即可. ...

  8. ReactiveCocoa与Functional Reactive Programming

    转自 http://blog.leezhong.com/ios/2013/06/19/frp-reactivecocoa.html Functional Reactive Programming(以下 ...

  9. Excel 二级下拉菜单

    http://jingyan.baidu.com/article/cd4c2979f31967756f6e6066.html http://hi.baidu.com/chenshake/item/e1 ...

  10. Android学习之AsyncTask

    我们在<Android学习之Handler消息传递机制>(http://www.cnblogs.com/zhouhb/p/5812447.html)已提到过,Android只允许UI线程修 ...