VB.net 2010 视频教程 VB.net 2010 视频教程 python基础视频教程
SQL Server 2008 视频教程 c#入门经典教程 Visual Basic从门到精通视频教程
当前位置:
首页 > Python基础教程 >
  • 加点JavaScript魔法

01

服务器支持

 

在深入研究客户端之前,让我们先了解一下支持这些用户弹窗所需的服务器端的工作。用户弹窗的内容将由新路由返回,它是现有个人主页路由的简化版本。视图函数如下:

app/main/routes.py:用户弹窗视图函数

  •  
  •  
  •  
  •  
  •  
@bp.route('/user/<username>/popup')@login_requireddef user_popup(username):    user = User.query.filter_by(username=username).first_or_404()    return render_template('user_popup.html', user=user)

该路由将被附加到 /user/<username>/popup URL,并且将简单地加载所请求的用户,然后渲染到模板中。该模板是个人主页的简化版本:

app/templates/user_popup.html:用户弹窗模板

  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
<table class="table">    <tr>        <td width="64" style="border: 0px;"><img src="{{ user.avatar(64) }}"></td>        <td style="border: 0px;">            <p>                <a href="{{ url_for('main.user', username=user.username) }}">                    {{ user.username }}                </a>            </p>            <small>                {% if user.about_me %}<p>{{ user.about_me }}</p>{% endif %}                {% if user.last_seen %}                <p>{{ _('Last seen on') }}:                    {{ moment(user.last_seen).format('lll') }}</p>                {% endif %}                <p>{{ _('%(count)d followers', count=user.followers.count()) }},                   {{ _('%(count)d following', count=user.followed.count()) }}</p>                {% if user != current_user %}                    {% if not current_user.is_following(user) %}                    <a href="{{ url_for('main.follow', username=user.username) }}">                        {{ _('Follow') }}                    </a>                    {% else %}                    <a href="{{ url_for('main.unfollow', username=user.username) }}">                        {{ _('Unfollow') }}                    </a>                    {% endif %}                {% endif %}            </small>        </td>    </tr></table>

 

当用户将鼠标指针悬停在用户名上时,随后小节中编写的JavaScript代码将会调用此路由。客户端将服务器端返回的响应中的html内容显示在弹出窗口中。当用户移开鼠标时,弹出窗口将被删除。听起来很简单,对吧?

如果你想了解弹窗像什么样,现在可以运行应用,跳转到任何用户的个人主页,然后在地址栏的URL中追加 /popup 以查看全屏版本的弹出窗口内容

02

popover 组件

 

第十一章中,我向你介绍了可便捷地创建精美网页的Bootstrap框架。到目前为止,我只使用了这个框架的一小部分。Bootstrap捆绑了许多常见的UI元素,所有这些元素都在地址为 https://getbootstrap.com 的Bootstrap文档中有demo和示例。其中一个组件是Popover(弹窗),在文档中将其描述为“用于容纳辅助信息的小的覆盖窗口”。这正是我需要的!

大多数bootstrap组件都是通过HTML标记定义的,该标记引用Bootstrap CSS的定义内容来添加漂亮的样式。一些高级的组件还需要JavaScript。应用程序在网页中包含这些组件的标准方式是在适当的位置添加HTML,然后为需要脚本支持的组件调用JavaScript函数,以便初始化或激活它。popover组件确实需要JavaScript的支持。

要做弹窗的HTML部分非常简单,你只需要定义将触发弹窗的元素。就我而言,就是处理每条用户动态中出现的可点击的用户名。 app/templates/_post.html子模板具有已定义的用户名:

  •  
  •  
  •  
<a href="{{ url_for('main.user', username=post.author.username) }}">    {{ post.author.username }}</a>

 

现在根据popover文档,我需要调用每个链接上的popover() JavaScript函数,就像上面出现在页面上的链接一样,这才能初始化弹出窗口。初始化调用接受许多配置弹出窗口的选项,包括传递想要在弹出窗口中显示的内容,以及使用什么方法触发弹出窗口出现或消失(单击,悬停在元素上等),如果内容是纯文本或HTML,那么在文档中可以找到更多的选项。不幸的是,在阅读完这些信息之后,我的疑惑更多了,因为这个组件看起来并没有按照我需要的方式工作。以下是我实现此功能需要解决的问题列表:

  • 在页面中会有很多用户名链接,每条用户动态都会显示一个。我需要有一种方法可以在页面渲染后用JavaScript中找到所有这些链接,以便我可以将它们初始化为弹出窗口。

  • Bootstrap文档中的popover示例都将目标HTML元素的data-content属性设置为popover的内容,因此当触发悬停事件时,Bootstrap需要做的只是显示弹出窗口。这对我来说要做的就不止这些了,因为我想对服务器进行Ajax调用以获取内容,并且只有当收到服务器的响应时,我才希望弹出窗口出现。

  • 使用“悬停”模式时,只要你将鼠标指针放在目标元素中,弹出窗口就会保持可见状态。当你移开鼠标时,弹出窗口将消失。这具有糟糕的副作用,即如果用户想要将鼠标指针移动到弹出窗口中,弹出窗口将消失。我需要找出一种方法来将悬停行为扩展为包含弹出窗口,以便用户可以移动到弹出窗口中,例如,单击那里的链接。

在开发基于浏览器的应用程序时,事情变得越来越复杂的情况,实际上并不罕见。你必须非常仔细地考虑DOM元素如何相互作用,并使其行为方式提供良好的用户体验。

03

在页面加载完成后执行函数

 

很明显,我将需要在每个页面加载后立即运行一些JavaScript代码。我要运行的函数将搜索页面中用户名的所有链接,并使用Bootstrap中的弹出窗口组件配置它们。

jQuery JavaScript库作为Bootstrap的依赖项加载,因此我将利用它。当使用jQuery时,你可以用$(...)封装来注册一个函数,函数将会在页面加载完毕后运行。我可以将它添加到app/templates/base.html模板中,以便它可以在应用程序的每个页面上运行:

app/templates/base.html:页面加载完毕后运行函数

  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
...<script>    // ...
    $(function() {        // write start up code here    });</script>

正如你所看到的,我已经在<script>元素中添加了我的启动函数,而在第十四章中,我已在该元素中定义了中的translate()函数

 

04

使用 DOM 选择器选中元素

 

第一个要解决的问题是创建一个JavaScript函数来查找页面中的所有用户链接。这个函数将在页面加载完成时运行,并且当完成时,将为所有页面配置悬停和弹出行为。现在我要集中精力来寻找链接。

回顾第十四章,在实时翻译中被调用的HTML元素具有唯一的ID。例如,ID = 123的用户动态中具有id="post123"属性。然后使用jQuery,在JavaScript中使用表达式$('#post123')在DOM中定位此元素。 $()函数功能非常强大,并且具有相当复杂的查询语言来搜索DOM元素,可以参考CSS Selectors

我用于翻译功能的选择器旨在使用id属性查找一个具有唯一标识符的特定元素。识别元素的另一种方法是使用class属性,它可以分配给页面中的多个元素。例如,我可以用class="user_popup"标记所有的用户链接,然后我可以通过$('.user_popup')获取这些元素的列表(CSS选择器中,#前缀代表查询id属性,.前缀代表查询class属性)。在本处,返回值将是具有该类的所有元素的集合

05

弹窗和 DOM 元素

 

通过使用Bootstrap文档中的弹出窗口示例并在浏览器的调试器中检查DOM,我确定Bootstrap将弹出窗口组件创建为DOM中目标元素的同级元素。正如我上面提到的,这会影响悬停事件的行为,只要用户将鼠标从<a>链接移动到弹出窗口本身,就会触发“鼠标移出”事件。

我可以扩展悬停事件以包含弹出窗口,就是将弹出窗口作为目标元素的子元素,这样悬停事件就会继承。通过查看文档中的弹出选项,可以通过在container选项中传递父元素来完成此操作。

将popover作为悬停元素的子元素可以很好地用于按钮或一般的<div><span>元素,但在我的情况下,popover的target将是显示用户名的可点击链接的<a> 元素。使popover成为<a>元素的子元素的问题是,弹出窗口将获得<a>父元素的链接行为。最终的结果是这样的:

  •  
  •  
  •  
  •  
<a href="..." class="user_popup">  username  <div> ... popover elements here ... </div></a>

为了避免弹出窗口出现在<a>元素中,我要使用的是另一个技巧。我要将<a>元素封装在<span>元素中,然后将悬停事件和弹出窗口与<span>相关联。由此产生的结构将是:

 

  •  
  •  
  •  
  •  
  •  
  •  
<span class="user_popup">    <a href="...">        username    </a>