Demo体验:计时器 – Hello, Flask!
难度:1
涉及知识点:URL变量
– – – – –
我们经常在一些网站上看到倒计时,比如购物网站上的秒杀倒计时,或是考试网站上的距离高考还剩多少天……
我们今天就用Flask和JavaScript(jQuery)来实现一个在线计时器,具体的User Strory:
- 可以在首页点击不同的时间按钮进入计时
- 计时结束后会有弹窗和铃声提示
- 可以在输入框里输入参数进入相应的计时,比如“34、23s、20m、2h”
- 可以通过在url里传入时间来开始计时,比如:
- “timertimer.herokuapp.com/10s”会进入一个10秒的计时。
- “timertimer.herokuapp.com/25m”会进入一个25分钟的计时。
- “timertimer.herokuapp.com/2h”会进入一个2小时的计时。
项目结构
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|-Timer-Flask 项目名称 |-app.py |-templates/ 模板文件夹 |-index.html |-static/ |-beep.mp3 计时结束铃声 |-favicon.ico 站点图标 |-style.css |-js/ |-progressbar.js |-jquery.min.js |-venv/ 虚拟环境 |
实现代码
主程序:app.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
import re from flask import Flask, render_template, url_for, redirect, request, flash app = Flask(__name__) app.config['SECRET_KEY'] = 'a very secret string' @app.route('/') def index(): return redirect(url_for('timer', num=11*60+11)) @app.route('/<int:num>s') @app.route('/<int:num>') def timer(num): return render_template('index.html', num=num) @app.route('/custom', methods=['GET', 'POST']) def custom(): time = request.form.get('time', 180) # 使用正则表达式来验证输入的字符 m = re.match('\d+[smh]?$', time) if m is None: flash(u'请输入一个有效的时间,例如34、20s、15m、2h') return redirect(url_for('index')) if time[-1] not in 'smh': return redirect(url_for('timer', num=int(time))) else: type = {'s': 'timer', 'm': 'minutes', 'h': 'hours'} return redirect(url_for(type[time[-1]], num=int(time[:-1]))) @app.route('/<int:num>m') def minutes(num): return redirect(url_for('timer', num=num*60)) @app.route('/<int:num>h') def hours(num): return redirect(url_for('timer', num=num*3600)) @app.errorhandler(404) def page_not_fouond(e): flash(u'访问地址出错了,鼠标放在问号上了解更多: )') return redirect(url_for('timer', num=244)) |
计时的功能主要用JavaScript(jQuery)实现,在index.html,传递变量给JavaScript:
1 2 3 4 5 |
{% block scripts %} <script> var Minutes = {{ num }}; </script> {% endblock %} |
另外,在这个APP里,因为表单很小,所以没有使用Flask-WTF。表单部分:
1 2 3 4 |
<form method="POST" action="{{ url_for('custom') }}" style="display:inline"> <input name="time" class="time-input" placeholder="example: 12/30s/20m/2h"> <input type="submit" class="startButton" value="START"> </form> |
然后在视图函数里,我使用request来获取数据,使用正则表达式验证数据:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
@app.route('/custom', methods=['GET', 'POST']) def custom(): # 设置180为默认值,避免提交空白表单产生400错误 time = request.form.get('time', 180) # 使用正则表达式验证数据 m = re.match('\d+[smh]?$', time) if m is None: flash(u'请输入一个有效的时间,例如34、20s、15m、2h') return redirect(url_for('index')) if time[-1] not in 'smh': return redirect(url_for('timer', num=int(time))) else: type = {'s': 'timer', 'm': 'minutes', 'h': 'hours'} return redirect(url_for(type[time[-1]], num=int(time[:-1]))) |
下一次会谈一下表单的几种不同的验证方式和一些处理技巧。
完整的实现见源码(链接在底部),欢迎fork和patch(或是star:)。
相关知识点
- URL变量
大部分现代的网站(app)都会有一个美观简洁的URL,比如http://www.example.com/user/kitty。在Flask里,我们通过在URL里设置变量来实现这个功能,比如说上面的URL,对应的路由就是:
1 |
app.route('/user/<username>') |
这个<variable_name>可以作为参数传递到视图函数里,我们还可以使用Flask提供的转换器,以<converter:variable_name>的形式来转换变量:
1 2 3 4 5 6 7 8 9 |
<span class="nd">@app</span><span class="o">.</span><span class="n">route</span><span class="p">(</span><span class="s1">'/user/<username>'</span><span class="p">)</span> <span class="k">def</span> <span class="nf">show_user_profile</span><span class="p">(</span><span class="n">username</span><span class="p">):</span> <span class="c1"># show the user profile for that user</span> <span class="k">return</span> <span class="s1">'User </span><span class="si">%s</span><span class="s1">'</span> <span class="o">%</span> <span class="n">username</span> <span class="nd">@app</span><span class="o">.</span><span class="n">route</span><span class="p">(</span><span class="s1">'/post/<int:post_id>'</span><span class="p">)</span> <span class="k">def</span> <span class="nf">show_post</span><span class="p">(</span><span class="n">post_id</span><span class="p">):</span> <span class="c1"># show the post with the given id, the id is an integer</span> <span class="k">return</span> <span class="s1">'Post </span><span class="si">%d</span><span class="s1">'</span> <span class="o">%</span> <span class="n">post_id</span> |
下面是Flask支持的转换器:
string | accepts any text without a slash (the default) |
int | accepts integers |
float | like int but for floating point values |
path | like the default but also accepts slashes |
any | matches one of the items provided |
uuid | accepts UUID strings |
使用这个特性,计时器实现了在地址后填入参数就可以进入相应的计时。
相关链接
DEMO:http://timertimer.herokuapp.com/
源码:https://github.com/helloflask/timer-flask
– – – – –
更多关于Flask的优质内容,欢迎关注Hello, Flask! – 知乎专栏。