翻譯:瘋狂的技術宅
原文標題:Creating a full-stack web application with Python, NPM, Webpack and React — Beauty and Functionality
原文連接:https://codeburst.io/creating...
本文首發微信公衆號:充實的腦洞。轉載需註明出處!javascript
若是你遵循前面的教程中的步驟,如今應該有了一個能夠工做的全棧Web應用程序框架。css
點擊直達前文 >> 【譯】一個小時搭建一個全棧Web應用框架(上)html
若是沒有,但仍是要繼續學習本教程,能夠到個人GitHub頁面下載代碼。前端
對於下一個魔術,咱們將把一個顯示「Hello World!」的簡單靜態頁面轉換成一個漂亮的單頁面WEB應用。 這個頁面可以與後端通訊,而且在收到新信息時當即更新,而無需用戶刷新頁面。咱們即將建立的頁面,在每次點擊按鈕時,會以隨機的歐洲語言返回「Hello」。java
這是咱們的頁面:python
爲了可以實現這一點,咱們須要先弄清楚如下的問題:react
每次調用 /hello
端點時,如何返回一個隨機的歐洲語言「Hello」。jquery
如何從服務器請求信息。webpack
如何將返回的信息無縫顯示給用戶,從而無需刷新頁面。git
如何在頁面上添加樣式,能夠在頁面上建立一個大的居中的按鈕並添加文本。
最後,咱們必須搞清楚應該如何添加一個背景圖像。
每當咱們與服務器上的 /hello
端點進行通話時,爲了可以請求一個隨機的歐洲語言「Hello」,必須更改 server/server.py 文件中的功能。每次調用它時,都不會返回靜態的「Hello World」,而是從「Hello」列表中選擇一個隨機語言的「Hello」。爲了實現這個功能,須要進行如下更改:
import random def get_hello(): greeting_list = [‘Ciao’, ‘Hei’, ‘Salut’, ‘Hola’, ‘Hallo’, ‘Hej’] return random.choice(greeting_list)
這個函數定義了一個歐洲語言的「hello」列表, 而後咱們調用這個函數時,使用 random.choice()
從列表中隨機選擇一個項目。
修改 hello()
函數,以便在每次調用它時返回get_hello()
。
@app.route("/hello") def hello(): return get_hello()
修改 /hello
以返回咱們感興趣的信息,咱們如今須要弄清楚如何從前端獲得這些信息。
把問題分解被認爲是良好的編程習慣。 只要有可能,你應該儘可能使本身的函數只作一件事情,而且作好。這點一樣適用於類。你能夠考慮將每一個函數或類都做爲單獨的組件。
React是爲組件化而設計的。這意味着它是用多個較小的部分來構建你的網站的。就像玩樂高同樣,能夠輕鬆地將一個組件替換成另一個,也能夠複用組件,這也能幫助其餘開發人員瞭解你的代碼。咱們應該努力的編寫可理解的代碼,由於這樣可使咱們的程序更容易維護和擴展。
考慮到組件化,咱們建立一個 Hello
類來處理咱們網頁上的問候語。該類將從服務器上的 /hello 端點點獲取一個 「Hello」 ,並將其顯示給用戶。 它也應該有一個「name」參數,這樣就能夠向某個具體的人進行問候。
經過更改 React App 類中的render函數,使其調用Hello
類,咱們就能夠很快的完成功能,而不是使用舊的代碼。傳遞名稱「Rimini」做爲參數。出於結構化的目的,咱們將把Hello
類放在一個 PageHeader
中。
前面咱們修改了 App
類使其可以調用 hello
類, 接下來須要建立 Hello
類。在 js/
目錄下建立一個名爲 hello.jsx
的文件, 在此文件中定義一個名爲 hello
的類。
export default class Hello extends React.Component { constructor(props) { super(props); this.state = {greeting: 'Hello ' + this.props.name}; // This binding is necessary to make `this` work in the callback this.getPythonHello = this.getPythonHello.bind(this); } }
在這一點上,你可能對構造函數中發生了什麼有不少疑問。
在 React 中有一種叫作組件和道具的東西。 Props是建立時傳遞給構造函數的不可變參數。 道具是公開的,修改他們將違反 React 的基本使用原則。狀態是內部的,可變的。每次更新狀態時,都會在UI中從新展示。若是但願更深刻地瞭解其運做方式,我強烈建議你閱讀React文檔中有關生命週期和狀態的部分。
咱們將在Hello
類中添加一個名爲personaliseGreeting()
的函數。 當咱們點擊按鈕得到一個新的問候語時,它將會處理網頁上的問候語的更新操做。 請注意,咱們使用this.setState()
與名爲「greeting」的key。你必須使用這個語法才能讓 React 自動刷新網頁上的「greeting」狀態。
personaliseGreeting(greeting) { this.setState({greeting: greeting + ' ' + this.props.name + '!'}); }
爲了讓問候語出如今頁面上,必須在render
函數中調用「{this.state.greeting}」
。咱們還必須添加一個帶有回調函數的按鈕,這個函數叫作getPythonHello()
,咱們很快就會實現它。這個函數在調用使用Python編寫的後端時,將會獲得一個新的「Hello」。
render () { return ( <h1>{this.state.greeting}</h1> <hr/> <Button bsSize="large" bsStyle="danger" onClick={this.getPythonHello}> Say Hello! </Button> ) }
請注意,我已經將標題和按鈕HTML內嵌到了個人代碼中,因此能夠很輕鬆地控制他們在頁面上的最終位置。
由於JavaScript中的類方法沒有作默認綁定,因此當咱們想在函數回調中使用「this」時,就必須在構造函數中建立一個綁定。不然「this」將會是 undefined 的。 這適用於在 JavaScript 中調用without()
的狀況。一個典型的例子就是 render()
中的 「onClick = {this.getPythonHello}」
。
React 沒有提供執行HTTP請求的內置方式。爲了可以從服務器請求信息,咱們將不得不找一個能夠作這件事的庫。 一個最簡單的方法就是引入 jQuery 庫。jQuery 是一個 javascript 庫,經過在$符號後面提供縮寫函數來簡化標準的 JavaScript 功能。
首先安裝jQuery依賴關係:
$ npm i jquery --save-dev
將 jQuery 依賴添加到要使用的 React 文件中,也就是 Hello.jsx 中。應該將此依賴添加到 Hello
類的定義前面。
var $ = require(‘jquery’);
將查詢依賴添加到React文件中意味着能夠在本身的React代碼中使用標準的 jQuery 函數,只要它們以咱們剛剛定義的「$」變量開始。下面讓咱們用它來從服務器獲取一個「Hello」。
咱們將使用 HTTP 協議的 GET 請求獲取信息。GET 實質上是HTTP請求的「只讀」模式。能夠用來獲取信息,可是不能要求服務器更改它。
在 hello.jsx 文件中的Hello
類中添加如下函數:
getPythonHello() { $.get(window.location.href + 'hello', (data) => { console.log(data); this.personaliseGreeting(data); }); }
此函數經過jQuery 的 GET請求,鏈接 /hello
端點。而後獲得從服務器返回的一個歐洲語言的「hello」信息,再它打印到瀏覽器的開發控制檯,最後將它傳遞給Hello
類中的另外一個函數,調用 personaliseGreeting()
。
當 rebuild 前端代碼(npm run watch),並從新啓動 python 服務器後。 應該能看到如下內容:
有一行問候語,一個按鈕,點擊按鈕能夠更改問候語。 這個頁面看起來很不錯,由於咱們在index.html中包含了Bootstrap樣式。
咱們終於有了一個可以與用戶交互的產品。若是咱們願意,就能夠到此爲止了,並對本身說:我對這些成就感到滿意。不過就我我的而言,我更喜歡在個人Web應用中添加一些設計元素,讓他們變得更加漂亮。因此,咱們將用CSS使標題可以覆蓋整個屏幕,而不是在頁面的頂部。CSS是爲HTML設計的一種樣式語言,它的做用至關於在Word文檔中更改字體大小,樣式和位置。
爲了可以在咱們的WEB應用中使用CSS,必須安裝一些加載器和插件,並將它們添加到Webpack配置文件中。這是由於 Webpack 默認只能處理JavaScript。
安裝下列插件:
css-loader
style-loader
extract-text-webpack-plugin
css-loader 和 style-loader 可以使 Webpack 處理 CSS。 經過添加這些加載器,Webpack 將可以將咱們須要的任何 CSS 綁定到 bundle.js 中。 不過在這裏存在一個問題,JavaScript 和 CSS 將不會在你的頁面上單獨進行加載,這可能致使 UI 組件在 JavaScript 加載以前沒法顯示。這點不好勁,由於在糟糕的網絡上,咱們辛辛苦苦設計出來的頁面可能會加載的很是緩慢。
不過能夠經過添加 extract-text-webpack-plugin 來解決這個問題。 這個插件可以將 CSS 分解成一個單獨的包,咱們能夠把它附加到 HTML 上。 這樣就可使 CSS 再次獨立於 JavaScript 進行加載。
在你的webpack.config.js
文件的 modules.rules
部分添加下面的CSS規則:
{ test: /\.css$/, use: ExtractTextPlugin.extract({ fallback: 'style-loader', use: 'css-loader', }) },
將ExtractTextPlugin插件添加到 webpack.config.js
(若是您感到困惑,請查看個人 webpack 文件)。注意,在建立時,須要將捆綁的CSS文件名傳給此插件。咱們將調用文件'styles.css'。
plugins: [ new ExtractTextPlugin('styles.css') ]
最後,咱們須要將 styles.css 包添加到index.html
中,以確保樣式被加載。將如下行添加到你的index.html
文件中的 head 部分(能夠參考個人代碼):
<link rel="stylesheet" href="dist/styles.css">
如今能夠確保咱們的設置能夠正確處理CSS了,咱們將在css文件夾中建立一個名爲fullstack.css 的文件。我已經添加了幾個不一樣的規則,以確保文本和按鈕出如今正確的位置,而且文本是大號的細體。
這是個人 fullstack.css 文件中的一個規則。 它使 「Hello Rimini」 文本變得愈來愈細:
.header-contents h1 { font-size: 120px; font-weight: 300; }
在建立 fullstack.css 文件以後,咱們須要將它添加到使用規則的 React 組件中,這樣它們才能生效。因爲標題在 App.jsx 中定義,因此須要添加如下代碼:
require('../css/fullstack.css');
fullstack.css 文件中的標題樣式如今將由 Webpack 拾取,並綁定到 styles.css 文件中。當咱們刷新頁面時,應該以下圖所示。注意,若是你用的瀏覽器不是 Chrome 的話,字體可能和圖中不同:
被CSS裝飾後的頁面
Webpack 自己並不理解圖像的概念。所以,咱們還須要添加一個能夠在Web應用程序中使用它們的加載程序。咱們須要安裝名爲「file-loader」的loader。
安裝 file-loader:
$ npm i file-loader --save-dev
將file-loader規則添加到 webpack.config.js 文件中的modules.rules部分:
{ test: /\.(png|svg|jpg|gif)$/, use: 'file-loader' }
將要使用的圖像添加到images/ folder。將其命名爲「header.jpg」。
爲了可以使圖像成爲網頁頭部的背景,咱們須要將其做爲背景圖像添加到 fullstack.css 文件的頁眉部分。
.page-header { background-image: url('../images/header.jpg'); background-repeat: no-repeat; background-position: center; background-size: cover; }
接下來要作的是把圖像加載到使用它的 React 文件中。若是沒有在 React 中顯式加載圖片,Webpack 將不會棒的它,也不會把它顯示在頁面上。這種行爲不是很直觀,在我第一次在本身的應用中添加一個背景圖像時,曾經犯過這個錯誤。
在App.jsx中進行以下更改:
import HeaderBackgroundImage from '../images/header.jpg';
將此函數添加到你的App類:
addHeaderImg() { let headerBg = new Image(); headerBg.src = HeaderBackgroundImage; }
這個函數建立了一個新的Image對象,並將源設置爲你的標題圖片。
咱們須要作的最後一件事是,確保在渲染頁面時加載圖像。 這意味着咱們必須在render()
函數中調用 addHeaderImg()函數。
將下列代碼添加到render()
函數中:
{this.addHeaderImg()}
刷新瀏覽器窗口時,應該看到如下內容:
恭喜你!你已成功建立了一個全棧 Web 應用程序!
關注微信公衆號:充實的腦洞, 一個技術宅的保留地 | |
---|---|