首页 > Python基础教程 >
-
加点JavaScript魔法(2)
</span>
<div>
和<span>
元素是不可见的,因此它们是用于帮助组织和构建DOM的重要元素。 div
元素是块元素,有点像HTML文档中的段落,而<span>
元素是行内元素,它可以用于字词级别。本处,我决定使用<span>
元素,因为我要包装的<a>
元素也是行内元素。
因此,我将继续并重构我的app/templates/_post.html子模板以包含<span>
元素:
{% set user_link %}
<span class="user_popup">
<a href="{{ url_for('main.user', username=post.author.username) }}">
{{ post.author.username }}
</a>
</span>
{% endset %}
如果你想知道弹出式HTML元素在哪里,好消息是我不必操心这一点。当我在刚刚创建的<span>
元素上调用popover()
初始化函数时,Bootstrap框架会为我动态地插入弹出组件
06
鼠标悬停事件
正如我上面提到的,Bootstrap中的popover组件使用的悬停行为不够灵活,无法满足我的需求,但如果你查看trigger
选项的文档,则hover
只是其中一个可能的值。一个引起我注意的是manual
模式,在这种模式下,可以通过JavaScript调用手动显示或删除弹出窗口,这种模式可以让我自由地实现悬停逻辑,所以我将使用该选项并实现我自己的悬停事件处理程序,并以我需要的方式工作。
所以我的下一步是将一个“hover”事件附加到页面中的所有链接。使用jQuery,可以通过调用element.hover(handlerIn, handlerOut)
将悬停事件附加到任何HTML元素。如果在元素集合上调用这个函数,jQuery方便地将事件附加到所有元素上。这两个参数是两个函数,分别在用户将鼠标指针移入和移出目标元素时调用对应的函数。
app/templates/base.html:悬停事件
$(function() {
$('.user_popup').hover(
function(event) {
// mouse in event handler
var elem = event.currentTarget;
},
function(event) {
// mouse out event handler
var elem = event.currentTarget;
}
)
});
事件参数是一个事件对象,它包含了一些有用的信息。在本处,我使用event.currentTarget
来提取事件的目标元素。
浏览器在鼠标进入受影响的元素后立即调度悬停事件。针对弹出行为,你只想鼠标停留在元素上一段时间才能激活,以防当鼠标指针短暂通过元素但不停留在元素上时出现弹出闪烁。由于该事件不支持延迟,因此这是我需要自己实现的另一件事情。所以我打算在“鼠标进入”事件处理程序中添加一秒计时器:
app/templates/base.html:悬停延迟
$(function() {
var timer = null;
$('.user_popup').hover(
function(event) {
// mouse in event handler
var elem = event.currentTarget;
timer = setTimeout(function() {
timer = null;
// popup logic goes here
}, 1000);
},
function(event) {
// mouse out event handler
var elem = event.currentTarget;
if (timer) {
clearTimeout(timer);
timer = null;
}
}
)
});
setTimeout()
函数在浏览器环境中才可用。它需要两个参数,函数和毫秒单位的时间。 setTimeout()
的效果是函数在给定的延迟后被调用。所以我添加了一个函数(现在是空的),将在悬停事件的一秒钟后被调用。由于JavaScript语言中的闭包机制,此函数可以访问在外部作用域中定义的变量,例如elem
。
我将timer对象存储在hover()
调用之外定义的timer
变量中,以使timer对象也可以被“mouse out”处理程序访问。我需要这么做的原因是为了获得良好的用户体验。如果用户将鼠标指针移动到其中一个用户链接中,并在移动它之前停留了半秒钟,我不希望该timer继续运行并调用显示弹出窗口的函数。所以我的鼠标移出事件处理程序检查是否有一个活动的timer对象,如果有,就取消它
07
Ajax 请求
Ajax请求不是一个新话题了,因为我已经在第十四章中已介绍过这个主题,来作为实时语言翻译功能。当使用jQuery时,$.ajax()
函数向服务器发送一个异步请求。
我要发送到服务器的请求将具有类似 /user/<username>/popup 模式的URL,在本章开始时我已经将该URL添加到应用程序中。这个请求的响应将包含我需要在弹出窗口中插入的HTML。
关于这个请求的直接问题是我需要知道包含在URL中的“username”的值是什么。鼠标进入的事件处理函数是通用的,它将在页面中找到的所有用户链接,所以该函数需要从其上下文中确定用户名。
elem
变量包含悬停事件中的目标元素,它是包裹<a>
元素的<span>
元素。为了提取用户名,我可以从<span>
开始浏览DOM,移至第一个子元素,即<a>
元素,然后从中提取文本,这就是在网址中要使用的用户名 。使用jQuery的DOM遍历函数,可以很简单地做到:
elem.first().text().trim()
应用于DOM节点的first()
函数返回其第一个子节点。 text()
函数返回节点的文本内容。该函数不会对文本进行任何修剪,例如,如果在一行中有<a>
,在下一行中有文本,在另一行中有</a>
,text()
将返回文本周围的所有空白。为了消除所有空白并只留下文本,我使用了名为trim()
的JavaScript函数。
这就是我需要向服务器发出请求的所有信息:
app/templates/base.html:XHR请求
$(function() {
var timer = null;
var xhr = null;
$('.user_popup').hover(
function(event) {
// mouse in event handler
var elem = $(event.currentTarget);
timer = setTimeout(function() {
timer = null;
xhr = $.ajax(
'/user/' + elem.first().text().trim() + '/popup').done(
function(data) {
xhr = null
// create and display popup here
}
);
}, 1000);
},
function(event) {
// mouse out event handler
var elem = $(event.currentTarget);
if (timer) {
clearTimeout(timer);
timer = null;
}
else if (xhr) {
xhr.abort();
xhr = null;
}
else {
// destroy popup here
}
}
)
});
代码中,我在外部范围中定义了一个新变量xhr
。这个变量将保存我通过调用$.ajax()
来初始化的异步请求对象。不幸的是,当直接在JavaScript端构建URL时,我无法使用Flask中的url_for()
,所以在这种情况下,我必须显式连接URL的各个部分。