使用bootstrap框架的翻页组件时,记起在学习使用laravel框架的时候,只需要添加相应的功能代码,就可以直接使用翻页组件了,但缺少自定义,或者说自定义起来有点麻烦。
自己手搓翻页组件,不仅能加深对flask的认识,也更熟悉了前后代码之间的传递关系。
bootstrap翻页组件只有样式,如何把它变为自己想要的样子,做之前还需要在大脑里有个大概的形态。比如页面少时,有几页就显示几页,页数多时,就可以显示开始的和结束的页面,让人可以一目了然的知道,一共有多少页码。
页数少的时候,像这样:
页面多的时候,像这样:
这里面的数据,都是从omdb api里拉取的,详情可以看这个:flask之jinjia模板语法,拉取omdb api-CSDN博客
这次手搓翻页组件、控件,主要是为了自己的需求来做的。当当前页为第一页时,前翻按钮为禁用状态,当当前页为最后一页的时候,向后翻的按钮同样为禁用状态。
上代码:
python
from flask import Flask, render_template, request
import requests
import math
import json
app = Flask(__name__)
@app.route('/', methods=["GET"])
# @app.route('/?s=<s>&page=<page>', methods=["GET"])
def main():
s = request.args.get("s")
page = request.args.get("page")
if page is None:
page = 1
else:
page = int(request.args.get("page"))
if s is None:
s = 'superman'
# Here is your key: 4ee0241e
# OMDb API: http://www.omdbapi.com/?i=tt3896198&apikey=4ee0241e
# rawData = requests.get("http://www.omdbapi.com/?apikey=4ee0241e&s=batman&page=1")
rawData = requests.get(f"http://www.omdbapi.com/?apikey=4ee0241e&s={s}&page={page}")
movies = rawData.json()
pages = math.ceil(int(movies["totalResults"]) / 10)
data = dict(
movies=movies,
active1="active",
active2="",
pages=pages,
page=page,
s=s,
)
return render_template("index.html", data=data)
@app.route('/', methods=["POST"])
def search():
s = request.form["name"]
page = 1
rawData = requests.get(f"http://www.omdbapi.com/?apikey=4ee0241e&s={s}&page={page}")
movies = rawData.json()
pages = math.ceil(int(movies["totalResults"]) / 10)
data = dict(
movies=movies,
active1="active",
active2="",
pages=pages,
page=page,
s=s,
)
return render_template("index.html", data=data)
@app.route('/<imdbID>')
def movie_by_title(imdbID):
# rawData = requests.get("http://www.omdbapi.com/?apikey=4ee0241e&i={}".format(imdbID))
rawData = requests.get(f"http://www.omdbapi.com/?apikey=4ee0241e&i={imdbID}")
movie = rawData.json()
data = dict(
movie=movie,
active1="",
active2="active",
)
return render_template("movie.html", data=data)
if __name__ == '__main__':
app.run(debug=True)
这次的路由只有三种,一是"/"根目录,有get和post状态2个路由,还有一个搜索search的post表单提交后展示电影详情页面的路由'/<imdbID>'。
目录结构:
模板代码:
footer.html
html
<div class="mt-3">
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"
integrity="sha384-C6RzsynM9kWDrMNeT87bh95OGNyZPhcTNXj1NW7RuBCsyN/o0jlpcV8Qyq46cDfL"
crossorigin="anonymous"></script>
</div>
header.html
html
<meta charset="UTF-8">
<title>母版</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet"
integrity="sha384-T3c6CoIi6uLrA9TneNEoa7RxnatzjcDSCmG1MXxSR1GAsXEV/Dwwykc2MPK8M2HN" crossorigin="anonymous">
home.html
html
<!DOCTYPE html>
<html lang="en">
<head>
{% block head %}
{% include './common/header.html' %}
{% endblock %}
<style>
.card:hover {
box-shadow: 10px 5px 5px #ccc;
}
.active {
background: rgb(208, 216, 222);
}
.navbar {
--bs-navbar-padding-y: 0;
}
.nav-link {
padding: 20px;
}
.row > * {
padding-left: 0;
}
</style>
</head>
<body>
{% block nav %}
{% include './common/nav.html' %}
{% endblock %}
<div class="container mt-3">
<div class="row">
{% block content %}
{% endblock %}
</div>
</div>
{% block footer %}
{% include './common/footer.html' %}
{% endblock %}
</body>
</html>
nav.html
html
<div class="contain bg-body-tertiary">
<nav class="navbar navbar-expand-lg container">
<div class="container-fluid">
<a class="navbar-brand">电影</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse"
data-bs-target="#navbarSupportedContent"
aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
<li class="nav-item {{ data["active1"] }}">
<a class="nav-link" aria-current="page" href="/">首页</a>
</li>
<li class="nav-item {{ data["active2"] }}">
<a class="nav-link" href="javascript:(0)">详情</a>
</li>
</ul>
<form class="d-flex" role="search" method="post" action="{{ url_for('search') }}">
<input class="form-control me-2" type="search" name="name" placeholder="搜索影片" value="{{ data.s }}"
aria-label="Search">
<button class="btn btn-outline-success" type="submit">search</button>
</form>
</div>
</div>
</nav>
</div>
index.html
html
{% extends "common/home.html" %}
{% block content %}
{% for movie in data["movies"].Search %}
<div class="col text-center mt-3">
<div class="card" style="height: 510px;overflow: hidden;width: 240px;">
<img src="{{ movie.Poster }}" height="350" class="card-img-top" alt="...">
<div class="card-body">
<h5 class="card-title" style="height: 48px;">{{ movie.Title[:35] }}</h5>
<p class="card-text">{{ movie.Year }}</p>
<a href="/{{ movie.imdbID }}" class="btn btn-primary">详情</a>
</div>
</div>
</div>
{% endfor %}
{# 翻页 #}
{% if data.pages>0 %}
<div class="d-flex align-items-center justify-content-center">
<div class="mt-3 mb-5">
<nav aria-label="Page navigation example">
<ul class="pagination pagination-lg justify-content-center">
<li class="page-item {{ 'disabled' if data.page==1 else '' }}">
<a class="page-link" href="/?s={{ data.s }}&page={{ data.page - 1 }}"
aria-label="Previous">
<span aria-hidden="true"><<</span>
</a>
</li>
{% if data.pages<8 %}
{% for i in range(data.pages) %}
<li class="page-item"><a
class="page-link {{ 'disabled' if data.page == i + 1 else '' }}"
href="/?s={{ data.s }}&page={{ i + 1 }}">
{{ i + 1 }}</a>
</li>
{% endfor %}
{% elif data.pages>=8 %}
{% for i in range(3) %}
{% if data.pages - 5 > data.page %}
<li class="page-item"><a
class="page-link {{ 'disabled' if data.page == i + data.page else '' }}"
href="/?s={{ data.s }}&page={{ i + data.page }}">
{{ i + data.page }}</a>
</li>
{% else %}
<li class="page-item"><a
class="page-link {{ 'disabled' if data.page == i + data.pages - 5 else '' }}"
href="/?s={{ data.s }}&page={{ data.pages - 5 + i }}">
{{ i + data.pages - 5 }}</a>
</li>
{% endif %}
{% endfor %}
<li class="page-item}">
<a class="page-link" href="javascript:(0)">
<span aria-hidden="true">...</span>
</a>
</li>
{% for i in range(3)[::-1] %}
<li class="page-item"><a
class="page-link {{ 'disabled' if data.page == data.pages - i else '' }}"
href="/?s={{ data.s }}&page={{ data.pages - i }}">
{{ data.pages - i }}</a>
</li>
{% endfor %}
{% endif %}
<li class="page-item {{ 'disabled' if data.page==data.pages else '' }}">
<a class="page-link" href="#" aria-label="Next">
<span aria-hidden="true">>></span>
</a>
</li>
</ul>
</nav>
</div>
</div>
{% endif %}
{% endblock %}
movie.html
html
{% extends "common/home.html" %}
{% block content %}
<div class="d-flex align-items-center justify-content-center">
<div class="card mb-3" style="max-width: 1080px;">
<div class="row">
<div class="col-md-4">
<img src="{{ data["movie"].Poster }}" class="img-fluid rounded-start" alt="...">
</div>
<div class="col-md-8">
<div class="card-body">
<h5 class="card-title">{{ data["movie"].Title }}</h5>
<p class="card-text">Year:{{ data["movie"].Year }}</p>
<p class="card-text">Runtime:{{ data["movie"].Runtime }}</p>
<p class="card-text">Actors:{{ data["movie"].Actors }}</p>
<p class="card-text">{{ data["movie"].Actors }}</p>
<p class="card-text">{{ data["movie"].Year }}</p>
<p class="card-text"><small class="text-body-secondary">{{ data["movie"].Plot }}</small></p>
</div>
<div class="d-flex align-items-center justify-content-center">
<a href="{{ url_for("main") }}" class="btn btn-success">返回</a>
</div>
</div>
</div>
</div>
</div>
{% endblock %}
里面容易绕圈圈的是,首页默认会有搜索词及内容,点击搜索按钮后,也是跳转到首页页面,显示搜索的内容,翻页也是在首页模板里面进行翻页。之前考虑使用
url_for()
url_for函数来进行跳转,发现这样的话,在循环翻页按钮的时候,怎么批量生成翻页按钮难住我了。这样不如直接获取链接地址里面的参数,来实现页面跳转。如果单独写一个
'/?s=<s>&page=<page>'
这样的路由,发现根本不起作用,起作用的还是'/'这个路由,只有使用函数url_for才能指定路由函数名称,才会执行,否则就是'/'起作用了。