当前位置: 代码迷 >> 综合 >> 20.flask-pjax
  详细解决方案

20.flask-pjax

热度:95   发布时间:2023-09-12 05:38:38.0

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 PJAXapp = 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 PJAXapp = 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') %}

20.flask-pjax