使用 Vue.js 和 Flask 來構建一個單頁的App

在這個教程中,咱們將講解如何將vue.js單頁應用與Flask後端進行鏈接。html

通常來講,若是你只是想經過Flask模板使用vue.js庫也是沒有問題的。可是,其實是一個很明顯的問題那就是,Jinja(模板引擎)也和Vue.js同樣採用雙大括號用於渲染,但只是一個還算過的去的解決方案。前端

我想要一個不一樣的例子。若是我須要創建一個單頁應用程序(應用程序使用單頁組成,vue-router在HTML5的History-mode以及其餘更多好用的功能)用vue.js,由Flask提供Web服務?簡單地說應該這樣,以下所示:vue

Flask爲index.html服務,index.html包含個人vue.js App。python

在前端開發中我使用Webpack,它提供了全部很酷的功能。webpack

Flask有API端,我能夠從個人SPA訪問。ios

我能夠訪問API端,甚至當我爲了前端開發而運行Node.js的時候。git

聽起來是否是頗有趣?那讓咱們這樣動手作作吧。github

完整的源代碼,你能夠在這裏找到:web

https://github.com/oleg-agapov/flask-vue-spavue-router

客戶端

我將使用Vue CLI產生基本vue.js App。若是你尚未安裝它,請運行:

$ npm install -g vue-cli
複製代碼

客戶端和後端代碼將被拆分到不一樣的文件夾。初始化前端部分運行跟蹤:

$ mkdir flaskvue
$ cd flaskvue
$ vue init webpack frontend
複製代碼

經過安裝嚮導。個人設置是:

  1. Vue 只在運行時構建。

  2. 安裝Vue-router。

  3. 使用ESLint檢查代碼。

  4. 選擇一個ESLint 標準預設 。

  5. 不試用Karma + Mocha進行單位測試。

  6. 不使用Nightwatch創建端到端的測試。

ok,接着來:

$ cd frontend
$ npm install
# after installation
$ npm run dev
複製代碼

這就能夠開始安裝vue.js應用程序。讓咱們從添加一些頁面開始吧。

添加home.vueabout.vuefrontend/src/components文件夾。它們很是簡單,像這樣:

// Home.vue

<template>
<div>
<p>Home page</p>
</div>
</template>
複製代碼

and

// About.vue

<template>
<div>
<p>About</p>
</div>
</template>
複製代碼

咱們將使用它們正確地識別咱們當前的位置(根據地址欄)。如今咱們須要改變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'
})
複製代碼

若是你試着輸入localhost:8080localhost:8080/about,你應該看到相應的頁面。

咱們幾乎已經準備好構建一個項目,而且可以建立一個靜態資源文件包。在此以前,讓咱們爲它們從新定義一下輸出目錄。在frontend/config/index.js找到下一個設置:

index: path.resolve(__dirname, '../dist/index.html'),
assetsRoot: path.resolve(__dirname, '../dist'),
複製代碼

把它們改成

index: path.resolve(__dirname, '../../dist/index.html'),
assetsRoot: path.resolve(__dirname, '../../dist'),
複製代碼

因此/dist文件夾的HTML、CSS、JS會在同一級目錄/frontend 。如今你能夠運行 $ npm run build 建立一個包。

後端

對於Flask服務器,我將使用Python版本3.6。在 /flaskvue建立新的子文件夾存放後端代碼並初始化虛擬環境:

$ mkdir backend
$ cd backend
$ virtualenv -p python3 venv
複製代碼

爲了使虛擬環境中運行(MacOS):

$ source venv/bin/activate
複製代碼

在Windows中須要激活此文檔(http://pymote.readthedocs.io/en/latest/install/windows_virtualenv.html)。

在虛擬環境下安裝:

(venv) pip install Flask
複製代碼

如今讓咱們爲Flask服務端編寫代碼。建立根目錄文件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」**代碼略有不一樣。主要的區別是,咱們指定存儲靜態文件和模板位置在文件夾 /dist,以便和咱們的前端文件夾區別開。在根文件夾中運行Flask服務端:

(venv) FLASK_APP=run.py FLASK_DEBUG=1 flask run
複製代碼

這將啓動本地主機上的Web服務器:localhost:5000 上的FLASK_APP服務器端的啓動文件,flask_debug = 1將運行在調試模式。若是一切正確,你會看到熟悉的主頁,你已經完成了對Vue的設置。

同時,若是您嘗試輸入/about頁面,您將面臨一個錯誤。Flask拋出一個錯誤,說找不到請求的URL。事實上,由於咱們使用了HTML5的History-Mode在Vue-router須要配置Web服務器的重定向,將全部路徑指向index.html。用Flask作起來很容易。將現有路由修改成如下:

@app.route('/', defaults={'path': ''})
@app.route('/<path:path>')
def catch_all(path):
return render_template("index.html")
複製代碼

如今輸入網址localhost:5000/about 將從新定向到index.html和vue-router將處理路由。

添加404頁

由於咱們有一個一應俱全的路徑,咱們的Web服務器在如今已經很難遇上404錯誤,Flask將全部請求指向index.html(甚至不存在的頁面)。因此咱們須要處理未知的路徑在vue.js應用。固然,全部的工做均可以在咱們的路由文件中完成。

在frontend/src/router/index.js添加下一行:

const routerOptions = [
{ path: '/', component: 'Home' },
{ path: '/about', component: 'About' },
{ path: '*', component: 'NotFound' }
]
複製代碼

這裏的路徑'*'是一個通配符, Vue-router就知道除了咱們上面定義的全部其餘任何路徑。如今咱們須要更多的創造NotFound.vue文件在**/components**目錄。試一下很簡單:

// NotFound.vue

<template>
<div>
<p>404 - Not Found</p>
</div>
</template>
複製代碼

如今運行的前端服務器再次npm run dev,嘗試進入一些毫無心義的地址例如:localhost:8080/gljhewrgoh。您應該看到咱們的「未找到」消息。

添加API端

咱們的vue.js/flask教程的最後一個例子將是服務器端API建立和調度客戶端。咱們將建立一個簡單的Api,它將從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('/<path:path>')
def catch_all(path):

return render_template("index.html")
複製代碼

首先我導入random庫和jsonify函數從Flask庫中。而後我添加了新的路由 /api/random來返回像這樣的JSON:

{
"randomNumber": 36
}
複製代碼

你能夠經過本地瀏覽測試這個路徑:localhost:5000/api/random。

此時服務器端工做已經完成。是時候在客戶端顯示了。咱們來改變home.vue組件顯示隨機數:

<template>
<div>
<p>Home page</p>
<p>Random number from backend: {{ randomNumber }}</p>
<button @click="getRandom">New random number</button>
</div>

</template>
<script>
export default {
data () {
return {
randomNumber: 0
}
},

methods: {
getRandomInt (min, max) {
min = Math.ceil(min)
max = Math.floor(max)
return Math.floor(Math.random() * (max - min + 1)) + min
},

getRandom () {
this.randomNumber = this.getRandomInt(1, 100)
}
},

created () {
this.getRandom()
}

}

</script>
複製代碼

在這個階段,咱們只是模仿客戶端的隨機數生成過程。因此,這個組件就是這樣工做的:

  1. 在初始化變量 randomNumber等於0。
  2. 在methods部分咱們經過getRandomInt(min, max)功能來從指定的範圍內返回一個隨機數,getrandom函數將生成隨機數並將賦值給randomNumber
  3. 組件方法getrandom建立後將會被調用來初始化隨機數
  4. 在按鈕的單擊事件咱們將用getrandom方法獲得新的隨機數

如今在主頁上,你應該看到前端顯示咱們產生的隨機數。讓咱們把它鏈接到後端。

爲此目的,我將用axios庫。它容許咱們用響應HTTP請求並用Json返回JavaScript Promise。咱們安裝下它:

(venv) cd frontend
(venv) npm install --save axios
複製代碼

打開 home.vue 再在 <script> 部分添加一些變化:

import axios from 'axios'
methods: {
getRandom () {
// this.randomNumber = this.getRandomInt(1, 100)
this.randomNumber = this.getRandomFromBackend()
},

getRandomFromBackend () {
const path = `http://localhost:5000/api/random`
axios.get(path)
.then(response => {
this.randomNumber = response.data.randomNumber
})
.catch(error => {
console.log(error)
})

}

}
複製代碼

在頂部,咱們須要引用Axios庫。而後有一個新的方法getrandomfrombackend將使用Axios異步調用API和檢索結果。最後,getrandom方法如今應該使用getrandomfrombackend函數獲得一個隨機值。

保存文件,到瀏覽器,運行一個開發服務器再次刷新 localhost:8080。你應該看到控制檯錯誤沒有隨機值。但別擔憂,一切都正常。咱們獲得了CORS的錯誤意味着Flask服務器API默認會關閉其餘Web服務器(在咱們這裏,vue.js App是在 Node.js服務器上運行的應用程序)。若是你npm run build 項目,那在localhost:5000(如Flask服務器)你會看到App在工做的。可是,每次對客戶端應用程序進行一些更改時,都建立一個包並不十分方便。

讓咱們用打包了CORS插件的Flask,將使咱們可以建立一個API訪問規則。插件叫作FlaskCORS,讓咱們安裝它:

(venv) pip install -U flask-cors
複製代碼

你能夠閱讀文檔,更好的解釋你要使你的服務器怎麼樣使用CORS。我將使用特定的方法,並將**{「origins」: 「*」}**應用於全部/api/*路由(這樣每一個人均可以使用個人API端)。在run.py加上:

from flask_cors import CORS
app = Flask(__name__,
static_folder = "./dist/static",
template_folder = "./dist")
cors = CORS(app, resources={r"/api/*": {"origins": "*"}})
複製代碼

有了這種改變,您就能夠從前端調用服務端。

更新:

事實上,若是你想經過Flask提供靜態文件不須要CORS。感謝Carson Gee的下面的這一招。

這個主意是這樣的。若是應用程序在調試模式下,它只會代理咱們的前端服務器。不然(在生產中)只爲靜態文件服務。因此咱們這樣作:

import requests
@app.route('/', defaults={'path': ''})
@app.route('/<path:path>')
def catch_all(path):

if app.debug:

return requests.get('http://localhost:8080/{}'.format(path)).text

return render_template("index.html")
複製代碼

很優雅的魔法✨!

如今有了一個完整的全棧**(full-stack)應用程序,用您最喜好Vue.jsFlask**技術構建。

後記

最後,我想就如何改進這個解決方案談幾句話。

首先利用CORS,若是你想讓你的API端訪問外部的服務器。不然的話只須要使用代理服務器與前端開發技巧。

另外一個改進是避免客戶端硬編碼API路由。也許你須要考慮一些API端點的字典。所以,當您更改API路由時,只需刷新一個字典便可。前端仍然有一個有效的端點。

一般在開發過程當中,你將至少有2個終端窗口:一個是Flask和另外一個是vue.js。在生產中能夠擺脫Vue而只單獨運行Node.js服務器。

源代碼:https://github.com/oleg-agapov/flask-vue-spa

謝謝你的閱讀!

匯智網(www.hubwiz.com)小智原創翻譯!!!

分享一個Vue.js 2 的入門級全家桶系列教程:

  1. vue.js 2 入門與提升: xc.hubwiz.com/course/vue.…
  2. vuex 2 入門與提升: xc.hubwiz.com/course/vuex
  3. vue-router 2 入門與提升: xc.hubwiz.com/course/vuer…
  4. vue.js 2 工程化實踐: xc.hubwiz.com/course/vueg…

另外推薦一個flask的入門教程給你們:

深刻淺出 flask http://xc.hubwiz.com/course/562427361bc20c980538e26f

相關文章
相關標籤/搜索