5.7.3 源码分析
我们前面说了,弹出框和提示框几乎一模一样,而且弹出框是从提示框继承而来的,所以继承以后唯一要处理的不同的内容,就是上面说的两个不同点:
❑将默认事件设置为click。
❑模板设置步骤要重新写,因为设置了两个内容。
步骤1 立即调用的函数。此步骤与Modal插件的步骤1一样,此处不赘述。
步骤2 插件核心代码。主要是popover核心类函数的定义、默认参数设置、继承tooltip的原型方法、重载要处理不同逻辑的个别方法。核心摘要代码如下:
- var Popover = function (element, options) {
- this.init('popover', element, options) // 调用了从tooltip继承过来的原型方法
- // init,并传入了popover类型
- }
- // 如果tooltip没引用,抛错,因为其依赖于tooltip
- if (!$.fn.tooltip) throw new Error('Popover requires tooltip.js')
- // 除了继承tooltip的默认值外,下面的默认值覆盖了tooltip的默认值
- Popover.DEFAULTS = $.extend({}, $.fn.tooltip.Constructor.DEFAULTS, {
- placement: 'right', // 显示位置,默认在右方显示
- trigger: 'click', // 设置触发popover的事件
- content: '', // 默认显示内容
- template: '<div class="popover"><div class="arrow"></div><h3 class="popover-
- title"></h3><div class="popover-content"></div></div>' // popover显示的内容模板
- })
- // 继承tooltip的原型,含所有原型方法
- Popover.prototype = $.extend({}, $.fn.tooltip.Constructor.prototype)
- Popover.prototype.constructor = Popover // 恢复构造函数,以免使用tooltip的构造函数
- // 重载tooltip里的getDefaults方法:获取默认配置
- Popover.prototype.getDefaults = function () {};
- // 重载tooltip里的setContent方法:设置popover要显示的内容
- Popover.prototype.setContent = function (){};
- // 重载tooltip里的hasContent方法:判断popover是否有要显示的内容
- Popover.prototype.hasContent = function (){};
- // 重载tooltip里的getContent方法:获取要显示的content内容
- Popover.prototype.getContent = function (){};
- // 重载tooltip里的arrow方法:获取显示的小箭头
- Popover.prototype.arrow = function (){};
- // 重载tooltip里的tip方法:获取模板内容
- Popover.prototype.tip = function (){};
通过上述概要代码可以看出,就像我们从其他文章里看到的一样,首先继承了tooltip的原型,然后重新赋值其构造函数,最后再重载6个原型方法,分别用于处理:默认值、内容设置、小箭头设置等。详细源码如下:
- // 重载tooltip里的getDefaults方法:获取默认配置
- Popover.prototype.getDefaults = function () {
- return Popover.DEFAULTS
- }
- // 重载tooltip里的setContent方法:设置popover要显示的内容
- Popover.prototype.setContent = function () {
- var $tip = this.tip() // 获取模板内容
- var title = this.getTitle() // 获取title内容
- var content = this.getContent() // 获取要显示的内容
- // 给模板里的popover-title样式的元素添加内容,如果支持HTML,就设置HTML,否则设置text
- $tip.find('.popover-title')[this.options.html ? 'html' : 'text'](title)
- $tip.find('.popover-content')[ // 对于HTML对象使用append,用于维护JS事件
- this.options.html ? (typeof content == 'string' ? 'html' : 'append') : 'text'
- ](content)
- // 正式显示之前,如果有多余的样式,全部删除,后面会根据状态再添加
- $tip.removeClass('fade top bottom left right in')
- // 由于IE8不支持empty伪类选择器,所以需要手动判断:如果title没有值,则隐藏该元素
- if (!$tip.find('.popover-title').html()) $tip.find('.popover-title').hide()
- }
- // 重载tooltip里的hasContent方法:判断popover是否有要显示的内容
- Popover.prototype.hasContent = function () {
- return this.getTitle() || this.getContent() // title和content任何一个有内容,
- 即认为popover有内容
- }
- // 重载tooltip里的getContent方法:获取要显示的content内容
- Popover.prototype.getContent = function () {
- var $e = this.$element // 所单击的触发元素
- var o = this.options // 传入的选项
- // 如果data-content属性有值,就使用它作为内容
- // 否则,再判断如果options里的content属性是function,就将其调用结果作为内容
- // 如果上述两者都不是,直接将options里的content属性作为内容返回
- return $e.attr('data-content')
- || (typeof o.content == 'function' ?
- o.content.call($e[0]) :
- o.content)
- }
- // 重载tooltip里的arrow方法:获取显示的小箭头
- Popover.prototype.arrow = function () {
- return this.$arrow = this.$arrow || this.tip().find('.arrow')
- }
- // 重载tooltip里的tip方法:获取模板内容
- Popover.prototype.tip = function () {
- if (!this.$tip) this.$tip = $(this.options.template)
- // 如果$tip不存在,则用options里的template模板
- return this.$tip
- }
步骤3 jQuery插件定义。在jQuery上定义$.fn.tpopoverab插件,没有什么特殊的地方。代码如下:
- var old = $.fn.popover
- // 保留其他库的$.fn.popover代码(如果定义的话),以便在noConflict之后,可以继续使用该老代码
- $.fn.popover = function (option) {
- return this.each(function () { // 根据选择器,遍历所有符合规则的元素
- var $this = $(this) // this赋值一个变量,防止作用域改变
- var data = $this.data('bs.popover') // 查询当前元素上是否已经有了popover实例
- // 如果option是对象,说明是参数集合,在new popover的时候传入
- var options = typeof option == 'object' && option
- if (!data && option == 'destroy') return
- // 如果没有popover实例,就初始化一个,并传入this
- if (!data) $this.data('bs.popover', (data = new Popover(this, options)))
- // 如果option是字符串,说明传入的是一个方法,直接调用该方法
- if (typeof option == 'string') data[option]()
- });
- }
- $.fn.popover.Constructor = Popover // 重设插件构造器,可以通过该属性获取插件的真实类函数
步骤4 防冲突处理。此步骤与Modal插件的步骤4一样,此处不赘述。
步骤5 绑定触发事件。与提示框插件一样,由于性能问题,没有定义绑定触发事件的代码。