20.flask-pjax

本文介绍Pjax技术的概念及其在Flask框架中的实践。Pjax通过局部刷新页面内容来提升用户体验,同时解决了单页面应用中SEO和URL对应的问题。文章详细展示了如何在Flask项目中配置和使用Pjax。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

flask-pjax

概念

什么是Pjax?
Pjax = history.pushState + Ajax
     = history.pushState + Async JS + XML(xhr?)

BOM对象history被增强了一波,主要是对历史栈的操作,以前只有replace, go之类的,都会跳转并刷新整个页面,现在有了pushState, replaceState等等单纯操作历史栈的方法,只是单纯修改历史栈里的内容,没有副作用(页面不会跳转刷新)

关于history对象的更多信息请查看MDN History

Pjax有什么用?
1.最初的单页面应用(SPA)

页面刷新不仅浪费资源(很多同级页面上大部分内容都是相同的,没必要重新加载这些重复内容),还影响用户体验(loadingloadingloading…)。局部刷新能够避免loading影响用户体验,从Ajax概念一出来就有人开始这么做了,把整站做成单页面应用(Single Page App,简称SPA),Ajax请求JSON,再局部刷新呈现数据,最初的SPA存在很多缺点:

  • 最大的问题:页面内容与URL不对应。

    这是致命的缺点,用户看到的内容与地址栏URL不对应,意味着内容无法分享传播(分享传播太重要了),浏览器前进/后退按钮也无法按照用户预期工作。

  • 其次:破坏SEO。

    纯Ajax实现的SPA对SEO有极大的消极影响,由于页面上很多内容都是Ajax请求之后js控制呈现的,蜘蛛看不到这些内容,也就根本不会被索引/收录。

2.pretty AJAX URL

为了解决SEO问题,Google提出了一种很丑(虽然名字叫pretty AJAX URL。。)的方法:#!

据说Twitter用过一个月,后来用户反馈说太丑了,再后来就不用了。这种很丑的url确实能解决上述的第2个问题,但是需要搜索引擎配合,Google认可这种方式,Google的蜘蛛会把mydomain.com/index.html#!article1mydomain.com/index.html#!article2当作两个不同的页面对待,服务给这种特殊URL的请求返回对应的页面即可,SEO问题没了。

但第一个问题还在,页面内容与URL仍然不对应,于是有了下面要说的Pjax。

3.Pjax

W3C提出了新的API,增强了history对历史栈的控制能力,能够直接修改地址栏URL,直到这时页面内容与URL才终于能够对应了。

每次局部刷新成功之后都调用history.pushState同步更新地址栏的URL(维护历史栈),这些URL都对应可以直接访问的页面,每个局部刷新动作都是由a标签触发的,js拦截默认跳转,再Ajax请求数据呈现数据,用户看到的是局部刷新和流畅的体验,蜘蛛看到的是普通的a标签页面跳转,页面展示的内容始终与直接访问URL得到的内容一致,致命缺点也不存在了。

如果各个浏览器支持性良好的话,Pjax能够完美支持单页面应用,如果浏览器不支持新API就把它当蜘蛛好了(目前好像没有好用的兼容方案,jq插件也无能为力),至于css/js冲突、内存泄露等等都是SPA本身的问题,成熟的SPA方案应该可以避免这些问题。

为什么要用Pjax?

在不影响SEO的前提下,局部刷新 + 本地缓存能够带来前所未有的快速体验,这是Pjax的绝对优势

Pjax适用于非纯移动端的单页面应用,能够实现流畅的用户体验,而且封装好的Pjax组件支持一些额外的功能,比如缓存、本地存储、动画等等,使用起来也很方便。

移动页面一般不存在频繁地大篇幅页面内容更新,而且移动页面很少需要考虑SEO,直接用Ajax即可。

安装

pip install flask-pjax

配置与用法

导入flask_pjax,创建实例化对象,并进行初始化。

from flask import Flask,render_template
from flask_pjax import PJAX

app = Flask(__name__)
pjax = PJAX()
pjax.init_app(app)

@app.route('/')
def index():
    return "Hello World"

if __name__ == "__main__":
    app.run()

设置基本模板

PJAX_BASE_TEMPLATE = "pjax.html"

创建base.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>基本模板</title>
</head>
<body>
{% block content %}

{% endblock %}
</body>
</html>

创建pjax.html

{% block content %} {% endblock %}

创建index.html

{% extends pjax('base.html') %}


{% block content %}
<div class="container">
    <p style="color: white;text-align: center">Welcome to the Index page.</p>
</div>

{% endblock %}

创建A.htmlB.htmlC.html

{% extends pjax('base.html') %}

{% block content %}

<div class="container">
  <p style="color: white;text-align: center">The A page.</p>
</div>

{% endblock %}
...
<div class="container">
  <p style="color: white;text-align: center">The B page.</p>
</div>
....
...
<div class="container">
  <p style="color: white;text-align: center">The C page.</p>
</div>
...

创建app.py

"""Testing Flask with PJAX."""
from flask import Flask, request, render_template
from flask_pjax import PJAX

app = Flask(__name__)
app.config["PJAX_BASE_TEMPLATE"] = "pjax.html"

pjax = PJAX()
pjax.init_app(app)


@app.route('/')
def home():
    return render_template('index.html')

@app.route('/A')
def a_pjax():
    return render_template('A.html')

@app.route('/B')
def b_pjax():
    return render_template('B.html')

@app.route('/C')
def c_pjax():
    return render_template('C.html')

if __name__ == '__main__':
    app.run()

这将为PJAX请求呈现pjax.html,为非PJAX请求呈现基础。

另外指定自定义PJAX基本模板:

{% extends pjax('base.html', pjax='/base/custom_pjax_template') %}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值