在实现显示投票用户的功能的时候 (看这里) , 想把用户名直接用 bootstrap3 的 popover 展示。需要在 popover 里面动态加载用户名列表。
开始时这么干的:
html:
<a href="javascript:void(0);" class="voted-users-popover" ....>显示该选项用户</a>
<a href="javascript:void(0);" class="voted-users-popover" ....>显示该选项用户</a>
<a href="javascript:void(0);" class="voted-users-popover" ....>显示该选项用户</a>
js:
// setup popover
$("a.voted-users-popover").each(function() {
var el = $(this);
el.popover({
html: true,
content: function() {
// call ajax and return the content html.
// 这里 ajax call 应该是设置 async = false.
},
});
});
ok, 好像是工作了. 但是 Debug 时发现在每次点击 voted-users-popover 时应用的日志却显示 两个 requests. 查看浏览器的 console 也发现,这里的函数被执行了两次:
content: function() {
console.log(">> getting voted users list...");
// call ajax and return the content html.
// 这里 ajax call 应该是设置 async = false.
},
这是不该出现的结果。
然后是,各种折腾... google..., 大半天后才想起 bootsrap3 的源代码!
找到 popover.js, 发现下面的代码:
// Popover 是继承/扩展自 Tooltip 的, getTitle() 在 tooltip.js 里面定义的
Popover.prototype.hasContent = function () {
return this.getTitle() || this.getContent()
// 如果提供 title 就不会执行 getContent()
}
Popover.prototype.getContent = function () {
var $e = this.$element
var o = this.options
return $e.attr('data-content')
|| (typeof o.content == 'function' ?
o.content.call($e[0]) :
o.content)
// 如果 content 是一个函数, 这里就会调用该函数返回 content
// 而在 popover/tooltip 执行 show 方法时, 是先检查有没有 content `hasContent()` 之后, 再调用 `setContent()` 来 render popover div 的. `setContent()` 当然也得执行 `getContent()`.
}
好吧!明显这样会调用两次 content 的函数!
所以,只有给一个 title 吧:
<a href="javascript:void(0);" title="显示该选项用户" class="voted-users-popover" ....>显示该选项用户</a>
<a href="javascript:void(0);" title="显示该选项用户" class="voted-users-popover" ....>显示该选项用户</a>
<a href="javascript:void(0);" title="显示该选项用户" class="voted-users-popover" ....>显示该选项用户</a>
如果不设置 title, 能不能解决? 试试 content 不由函数提供!那怎么动态加载 content ? html 里删除 title, js:
// setup popover
$("a.voted-users-popover").each(function() {
var el = $(this);
el.popover({
html: true,
content: '<center><i class="fa fa-spin fa-spinner"></i></center>',
});
// 调用 popover 的 shown 事件来加载内容
el.on('shown.bs.popover', function(){
//...
$.ajax({
// 这次不用 async = false 了!
success: function(data) {
if(good(data)) {
el.next().find("div.popover-content").html(html_from_data(data));
// popover div 在 el 的下面.
} else {
el.next().find("div.popover-content").html("");
}
},
})
});
});
ok, 好像也工作了,经测试没有两次 requests 了。
但也带来一个新的问题,动态内容是在 popover 弹出 (shown) 后加载的,也就是 popover div 的位置已经固定了,渲染内容后整体的位置可能不是你所期望的!
不过最后还是采用的后面的方案!因为可以方便地显示一个 loading... 菊花!
当然,还有第三种方案:
自己去实现一个类似 popover 的东西...
补充: 总结就是: 通过 $(e).popover({}) 初始化 popover 的 content 时,如果 没有初始化 e 的 title 且这个 content 是函数,那么它会被执行两次。