如果前端路由采用的 hash 模式,那么上面的方法就不奏效了,没有找到其他比较好的方法,但是我们可以修改 devServer 的 proxy 表来改变路由:
proxy: { '/user': { target: 'http://127.0.0.1:8080/user.html', changeOrigin: false, pathRewrite: { '^/user': '' } } }现在我们在开发服务器中访问 :8080/user 也就访问到了相应的界面。这样做就使得服务端和前端的多页面路由跳转是一致的。
当前端开发完成后,使用 yarn build 命令将会在根目录的 vtemplates 目录下创建前端要用到的界面文件和 JS 代码。只需使用 python app.py 启动服务器即可。
完成了访问页面的路由统一,接下来只需要处理前后端通信的 API 即可。
我们在 app.py 文件中添加一个用于处理前后端通信的蓝图 api:
# app.py api = Blueprint( 'api', __name__ ) @api.route('/home/signin', methods=['POST']) def home_signin(): username = request.form.get('username') password = request.form.get('password') resp = { 'status': 'success' } if username == 'test' and password == '1234': session['user'] = username else: resp['status'] = 'fail' return jsonify(resp) app.register_blueprint(api, url_prefix='/api')定义一个路由,以便可以响应相应的 POST 操作。
然后在前端项目 frontend 中添加一个用于通信的 src/api.js,内容如下:
import $ from 'jquery' export function fetchPost(url, params = {}) { return new Promise((resolve, reject) => { $.post(url, params).then( resp => { resolve( resp ); }).catch( error => { reject( error ); }); }); } export default { fetchPost: fetchPost }由于在 devServer 中我们已经定义了 api 地址的跨域访问,因此可以使用 JQuery,当然如果你更熟悉 axios,那么你可以引入 axios 替换掉 jquery。
然后我们在 /frontend/src/home/ 路径下再添加一个 api.js 文件,负责处理前后端的 api 路由:
# home/api.js import {fetchPost} from '../api.js' export const singin = function(params) { return fetchPost('/api/home/signin', params); }最后修改 /frontend/src/home/pages/Index.vue 文件,添加两个输入框和按钮,并且添加相应的数据,以下为该文件中的内容:
<template> <div> <hr /> This is Index Page In Home SPA. <form> <div> Username: <input type="text" v-model="username"/> </div> <div> Password: <input type="text" v-model="password"/> </div> <div> <button type="button" @click="toSignin()">SignIn</button> </div> </form> </div> </template> <script> import {signin} from '../api.js' export default { name: 'homeIndex', data() { return { username: null, password: null, } }, methods: { toSignin: function() { signin({ username: this.username, password: this.password }).then( resp => { if( resp.status === 'success' ) { window.location = '/user' } else { alert('Username or password is wrong.') } }) } } } </script> <style> .m-1 { margin: 5px; } </style>在该界面中输入一些错误的用户名或密码,将会在浏览器中弹出警告框,输入正确的用户名(test)和密码(1234)后,前端页面自动跳转到 /user 路径下。这样前后端结合的工作就完成了。我们还做了一个非常简陋的登录示例。最后,我们将写好的前端代码打包到相应目录下,在浏览器中输入 localhost:5000 访问我们的网站,可以正常的显示和跳转,和访问前端的开发服务器一样,只是所有服务都由 Flask 提供了。
拓展:利用 PyQt5 制作桌面应用既然使用 Python Flask 和 Vue 制作了一个前后端分离的网站应用,那么我们实际上可以考虑添加 PyQt5 组件,利用现有的代码制作一个基于 HTML5 的桌面应用,当然也可以直接通过在浏览器中输入 IP + 地址的方式访问这个桌面应用。
我们在项目根目录下新建一个 deskapp.py,内容如下:
from PyQt5.QtWidgets import QApplication from PyQt5.QtWebEngineWidgets import QWebEngineView from PyQt5.QtCore import QUrl def startWeb(): from app import app app.run() def main(argv): qtapp = QApplication(argv) from threading import Thread webapp = Thread(target=startWeb) webapp.daemon = True webapp.start() view = QWebEngineView() view.setWindowTitle('DeskApp') port = 5000 view.setUrl( QUrl("http://localhost:{}/".format(port))) view.show() return qtapp.exec_() import sys if __name__ == '__main__': main(sys.argv)使用 python deskapp.py 运行程序,就会显示一个桌面应用,在我们的网站应用规模较小时这样做没什么问题,但是最终应用的生产环境的 web app 可能使用的是 gevent.pywsgi.WSGIServer,并且后台可能需要处理的事情较多,这时有可能会出现界面闪烁的情况,如果出现了这种情况,可以参考 PyFladesk 这个项目使用的方式:使用 QThread 包装我们的 web 应用。由于 Python 中有 GIL 全局锁,所以它的多线程不是真正意义上的多线程,但是 QThread 是 Qt 提供的多线程机制,线程之间不会相互影响。
总结如果你只想在部分页面中使用 Vue,并且要在 Flask 的模板中使用 Vue,那么你需要让 Vue 使用不同的定界符,详见 specify delimiters for a vuejs component