譯者:楓林
鏈接:http://www.zcfy.cc/article/4491
原文:https://codeburst.io/full-stack-single-page-application-with-vue-js-and-flask-b1e036315532
在本教程中,我將向大家展示如何使用前端的 Vue.js 單頁面應(yīng)用和后端的 Flask 進行交互。
如果你只是想使用 Vue.js 庫和 Flask 模板基本上是沒什么問題的。但...好吧,其實還是有一個比較顯而易見的問題:跟 Vue.js 一樣,Jinji(模板引擎)也是使用雙大括號來渲染頁面,但已經(jīng)有一個很好的解決方案 在這里 了。
我想要一個跟上面方案有點不同的例子。如果我要一個用 Vue.js(使用單頁面組件,在 vue-router
開啟 HTML5 history 模式,還有使用其他一些非常棒的特性)框架的單頁面和 Flask 做后臺服務(wù)的應(yīng)用?應(yīng)該能按下面的要求工作:
Flask運行的服務(wù)可以訪問 index.html
首頁和 Vue.js 應(yīng)用
在前端開發(fā)環(huán)境,使用 Webpack 和它提供的很多非常棒的功能
可以從前端的單頁面應(yīng)用訪問 Flask 的 API 接口
以 Node.js 服務(wù)運行的前端開發(fā)環(huán)境同樣也可以訪問 API 接口
這看起來很有趣,不是嗎?那就讓我們開始吧。
你可以在github上查看所有的源代碼:
https://github.com/oleg-agapov/flask-vue-spa
我用 vue-cli 命令行工具搭建起 Vue.js 的基礎(chǔ)框架。如果你還沒有安裝,可以運行:
$ npm install -g vue-cli
客戶端和后端代碼將會放到不同的文件夾下,初始化前端部分執(zhí)行如下操作:
$ mkdir flaskvue
$ cd flaskvue
$ vue init webpack frontend
以下是我通過安裝向?qū)У捻椖吭O(shè)置:
Vue build?—?Runtime only (Vue 構(gòu)建的版本 - 運行時)
Install vue-router??—?Yes (安裝 vue-router? - 是)
Use ESLint to lint your code??—?Yes (使用 ESLint 校驗?zāi)愕拇a? - 是)
Pick an ESLint preset?—?Standard (選擇 ESList 的預(yù)置版本 - 標(biāo)準(zhǔn))
Setup unit tests with Karma + Mocha??—?No (使用 Karma + Mocha 設(shè)置單元測試? - 否)
Setup e2e tests with Nightwatch??—?No (使用 Nightwatch 設(shè)置端到端測試? - 否)
下一步:
$ cd frontend
$ npm install
# after installation
$ npm run dev
現(xiàn)在你可以開始設(shè)置 Vue.js 應(yīng)用了。讓我們先來添加些頁面吧。
添加 Home.vue
和 About.vue
到 frontend/src/components
文件夾。像如下簡單添加些內(nèi)容:
// Home.vue
Home pagep>
div>
template>
和
// About.vue
Aboutp>
div>
template>
我們將在本地驗證它們(通過地址欄訪問)。現(xiàn)在我們要改變 frontend/src/router/index.js
文件去一個個渲染我們的新組件:
import Vue from 'vue'
import Router from 'vue-router'
const routerOptions = [
{ path: '/', component: 'Home' },
{ path: '/about', component: 'About' }
]
const routes = routerOptions.map(route => {
return {
...route,
component: () => import(`@/components/${route.component}.vue`)
}
})
Vue.use(Router)
export default new Router({
routes,
mode: 'history'
})
現(xiàn)在如果輸入 localhost:8080
和 localhost:8080/about
你應(yīng)該看到相應(yīng)的頁面。
在我們構(gòu)建生成項目靜態(tài)資源前還需要修改它們的輸出路徑。在 frontend/config/index.js
找到下面的兩行
index: path.resolve(__dirname, '../dist/index.html'),
assetsRoot: path.resolve(__dirname, '../dist'),
然后成改如下內(nèi)容
index: path.resolve(__dirname, '../../dist/index.html'),
assetsRoot: path.resolve(__dirname, '../../dist'),
所以, 包含 html/css/js 靜態(tài)資源包的 /dist
文件夾和 /frontend
在同一級目錄下?,F(xiàn)在你可以運行 $ npm run build
去構(gòu)建項目了
Flask 后端,我將使用 3.6 版本的 python。在根目錄 /flaskvue
文件夾下為后端代碼和初始化虛擬環(huán)境創(chuàng)建新的子目錄:
$ mkdir backend
$ cd backend
$ virtualenv -p python3 venv
開啟虛擬環(huán)境執(zhí)行(mac系統(tǒng)):
$ source venv/bin/activate
在 Windows 上開啟請看這里 docs。
在虛擬環(huán)境中安裝 Flask 如下:
(venv) pip install Flask
現(xiàn)在讓我們開始寫 Flask 服務(wù)器端代碼。在根目錄下創(chuàng)建 run.py
文件:
(venv) cd ..
(venv) touch run.py
然后添加以下代碼到這個文件:
from flask import Flask, render_template
app = Flask(__name__,
static_folder = './dist/static',
template_folder = './dist')
@app.route('/')
def index():
return render_template('index.html')
上面的代碼和 Flask 入門教程 “Hello world” 上的代碼稍有不同。最主要的不同點在于我們詳細(xì)指明了前端的靜態(tài)和模板文件夾輸出到 /dist
文件夾。然后在根目錄下運行 Flask 服務(wù)。
(venv) FLASK_APP=run.py FLASK_DEBUG=1 flask run
這將會在 localhost:5000
開啟一個后臺服務(wù)。 FLASK_APP
指向服務(wù)啟動文件, FLASK_DEBUG=1
將會以調(diào)試模式運行。如果沒有錯誤,你將會看到熟悉的首頁,這樣,服務(wù)器就成功運行 Vue 應(yīng)用了。
與此同時如果你試圖訪問 /about
頁面將會出現(xiàn)一個錯誤。Flask 會拋出一個找不到請求地址的錯誤。實際上是因為在 vue-router
用了 HTML5 的 history 模式, 所以我們需要配置我們的后臺服務(wù)去重定向所有的路由都跳轉(zhuǎn)到 index.html
上。這在 Flask 上可以很簡單做到。做如下修改:
@app.route('/', defaults={'path': ''})
@app.route('/
def catch_all(path):
return render_template('index.html')
現(xiàn)在地址 localhost:5000/about
將會重定向到 index.html
和 vue-router
將會在它自己內(nèi)部處理。
因為在我們的后臺服務(wù)里設(shè)置捕捉所有路由是非常困難的,所以我們用 Flask 捕捉 404 錯誤會重定向 所有 請求到 index.html
(連同不存在的頁面)。在 Vue.js 應(yīng)用里處理未定義的路由。當(dāng)然,所有的工作均可在我們的路由文件設(shè)置。
在 frontend/src/router/index.js
增加一行:
const routerOptions = [
{ path: '/', component: 'Home' },
{ path: '/about', component: 'About' },
{ path: '*', component: 'NotFound' }
]
通配符 '*'
在 vue-router
里的含義是以上路由定義之外的情況?,F(xiàn)在我們需要在 /components
文件夾新建 NotFound.vue
文件。我簡單地創(chuàng)建它:
// NotFound.vue
404 - Not Foundp>
div>
template>
現(xiàn)在 通過 npm run dev
重新啟動前臺服務(wù)然后隨意輸入網(wǎng)址像 localhost:8080/gljhewrgoh
。你應(yīng)該看到 “Not Found” 兩個單詞。
我的 Vue.js/Flask 教程的最后一個例子將在后端創(chuàng)建一個 API 接口然后通過前端來調(diào)用它。我將創(chuàng)建一個隨機返回數(shù)字1到100的簡單端口。
打開 run.py
新增如下代碼:
from flask import Flask, render_template, jsonify
from random import *
app = Flask(__name__,
static_folder = './dist/static',
template_folder = './dist')
@app.route('/api/random')
def random_number():
response = {
'randomNumber': randint(1, 100)
}
return jsonify(response)
@app.route('/', defaults={'path': ''})
@app.route('/
def catch_all(path):
return render_template('index.html')
我首先從 Flask 資源庫導(dǎo)入 random
庫和 jsonify
函數(shù)。然后我增加一個返回 JSON 數(shù)據(jù)格式的新路由 /api/random
, 如下:
{
'randomNumber': 36
}
你可以通過地址: localhost:5000/api/random
來測試這個路由。
到這里,服務(wù)端的工作已經(jīng)完成了。該到客戶端上場了。我將修改 Home.vue
組件來顯示我的隨機數(shù)字:
Home page
Random number from backend: {{ randomNumber }}
<> @click='getRandom'>New random number
在這一步,我將在客戶端模擬隨機數(shù)的生成。所以,組件的工作過程如下:
初始變量 randomNumber
等于 0
在 methods
部分,我們用 getRandomInt(min, max)
函數(shù)從指定區(qū)間返回一個數(shù)字, getRandom
函數(shù)將調(diào)用上一個函數(shù)生成一個值賦給 randomNumber
之后在組件被創(chuàng)建時調(diào)用 getRandom
方法給 randomNumber
賦個初始數(shù)值
在按鈕點擊事件里,我們將觸發(fā) getRandom
方法去得到一個數(shù)值
現(xiàn)在,在首頁上你將看到由前端生成的隨機數(shù)。讓我們繼續(xù)來連接后端。
我將用 axios 庫來連接后端。它將允許我們創(chuàng)建能返回 Promise
對象的 HTTP 請求。我們先安裝它:
(venv) cd frontend
(venv) npm install --save axios
再次打開 Home.uve
,修改