本教程將帶大家一起學習使用react,首先我們會搭建開發環境(react+webpack),然后講解react相關的知識,再講到使用axios發起網絡請求,使用React-Router4作為前端路由,webpack打包生成app,最后使用nginx部署。
開發環境搭建
mkdir myreactapp
cd myreactapp
npm init
一路回車初始化package.json
安裝react react-dom
npm install react react-dom --save
安裝webpack 打包工具
npm install webpack webpack-cli --save-dev
安裝webpack-dev-server 調試服務器
npm install webpack-dev-server --save-dev
安裝babel插件 將ES6代碼轉換成ES5
npm install babel-core babel-loader babel-preset-es2015 babel-preset-react --save-dev
創建app文件夾,開發的代碼放在里面
創建build文件夾,打包后的文件放在里面
在app文件夾創建main.js,為app入口文件
import React from 'react';
import ReactDOM from 'react-dom';
ReactDOM.render(
<h1>hello,first react app</h1>,
document.getElementById('app')
);
在build文件夾創建index.html
<!DOCTYPE html>
<html>
<head lang="zh-CN">
<meta charset="UTF-8">
<title>my first react app</title>
</head>
<body>
<div id="app"></div>
<script src="/bundle.js"></script>
</body>
</html>
創建webpack.config.js并寫入內容
var path = require('path');
var webpack = require('webpack');
module.exports = {
entry: ['webpack/hot/dev-server', path.resolve(__dirname, './app/main.js')],
output: {
path: path.resolve(__dirname, './build'),
filename: 'bundle.js',
publicPath: '/'
},
devServer: {
inline: true,
port: 3000
},
module: {
rules: [
{
test: /\.js?$/,
exclude: /(node_modules|bower_components)/,
loader: 'babel-loader',
}
],
},
plugins: [
new webpack.HotModuleReplacementPlugin()
]
};
根目錄創建.babelrc文件 這個文件是用來設置轉碼的規則和插件的
{
"presets": ["es2015", "react"],
"env": {
"development": {
}
}
}
修改package.json scripts節點
添加"start": "webpack-dev-server --devtool eval --progress --colors --content-base build"
輸入npm start,啟動服務器,瀏覽器輸入http://localhost:3000 ,驗證是否出現hello,first react app
點擊F12審查元素
確實是我們在main.js里面寫的h1標簽和文字,加載到了id為app的dom節點里面
接下來我們創建兩個組件,分別是index和index_section,在app文件夾下創建components文件夾,當然如果項目大的話可以按頁面存放,即再建一個文件夾index代表這是index頁面的組件,建一個public文件夾放置公共組件,這里只新建index.js和index_section.js演示,
請注意,組件取名必須以大寫字母開頭。
import React from 'react'
import IndexSection from './index_section'
export default class Index extends React.Component{
constructor(props){
super(props);
}
render(){
return (
<div>
<h1>這是index.js</h1>
<IndexSection/>
</div>
);
}
}
import React from 'react'
export default class IndexSection extends React.Component{
constructor(props){
super(props);
}
render(){
return (
<section>
<h1>這是index_section.js</h1>
</section>
);
}
}
修改main.js
import React from 'react';
import ReactDOM from 'react-dom';
import Index from './components/index';
ReactDOM.render(
<Index/>,
document.getElementById('app')
);
點擊保存后,網頁自動刷新
當然,你也可以把index_section.js寫到index.js里面,注意,每個js文件都只能存在一個export default,所以新的index.js為
import React from 'react'
class IndexSection extends React.Component{
constructor(props){
super(props);
}
render(){
return (
<section>
<h1>這是index.js里面的index_section組件</h1>
</section>
);
}
}
export default class Index extends React.Component{
constructor(props){
super(props);
}
render(){
return (
<div>
<h1>這是index.js</h1>
<IndexSection/>
</div>
);
}
}
props
react是單向是數據流,使用props實現父組件向子組件傳值
props被用作初始化狀態,當一個組件初始化之后,它的props是只讀的,只有通過父組件重新渲染才可以把新的props傳入組件中
上面的Index組件為父組件,IndexSection為子組件,我們向子組件傳遞一些字符串
在Index的render方法里面修改
render(){
return (
<div>
<h1>這是index.js</h1>
<IndexSection name="子組件prop:name" age="子組件prop:age"/>
</div>
);
}
在IndexSection的render方法log一下它收到的值,使用console.log(this.props)輸出,再在render方法的return里面輸出一下它的這兩個值
render(){
console.log(this.props);
return (
<section>
<h1>這是index.js里面的index_section組件</h1>
<h1>{this.props.name}</h1>
<h1>{this.props.age}</h1>
</section>
);
}
state
state里面保存組件自身的狀態,在組件初始化的時候可以設定組件默認的state,在IndexSection的constructor方法里面設置它的默認state,并在render方法輸出
constructor(props){
super(props);
this.state = {name:"IndexSection自身的state:name",age:"IndexSection自身的state:age"};
}
render(){
console.log(this.state);
return (
<section>
<h1>這是index.js里面的index_section組件</h1>
<h1>{this.state.name}</h1>
<h1>{this.state.age}</h1>
</section>
);
}
與props不同的是,組件的state是可以改變的,通過使用this.setState()方法來修改組件的state,傳入的第一個參數可以是一個json對象:this.setState({name:"shane",sex:"male"});
,這里可以傳入初始state里面存在的屬性,也可以傳入一個不存在的屬性。在生命周期那里我們會驗證該方法。
第一個參數也可以是一個函數
setState((prevState, props) => {
return {"..." :" ...",...};
});
prevState為更新前的state,props為當前的props,return的為修改后的state
setState({a:1},()=>...)
還可以接受第二個參數,為一個函數,在setState()調用完成后調用,相當于生命周期的componentDidUpdate
setState()
方法通常是異步的,并且連續多次調用 setState 來更新同一個字段時,只有最后一次setState()才會生效。如果setState()后需要立即獲取更新后的數據,可以使用setTimeout函數來延遲0秒或者componentDidUpdate
方法來獲取。
但是請注意,在一些方法里面不可以使用this.setState()
,錯誤使用將會造成循環調用,造成瀏覽器卡死崩潰,將在生命周期里面講到
生命周期
每一個組件都有若干個生命周期的方法(在進程中的你可以重寫在特殊的時刻),方法中帶Will前綴在某件事情發生之前被調用,帶Did的前綴的在某件事發生之后被調用。
mounting
以下方法將被調用當一個實例組件被創建并插入到dom中的時候
constructor(props) //使用super(props) 后構造函數里面才可以使用this.props ,生命周期中只執行一次
componentWillMount() //組件即將掛載,生命周期中只執行一次
render() //渲染,生命周期中可執行多次
componentDidMount() //組件第一次掛載完成,生命周期中只執行一次
updating
屬性或者狀態的改變會觸發更新,以下方法會在組件正進行重新渲染的過程中觸發。
componentWillReceiveProps(nextprops ) //將收到新的props,nextprops為新的props,生命周期中可執行多次
shouldComponentUpdate(nextProps, nextState ) //比較新舊props和state返回true/false來控制是否更新,生命周期中可執行多次
componentWillUpdate(nextProps, nextState) //組件將更新,生命周期中可執行多次
render() //渲染,生命周期中可執行多次
componentDidUpdate(prevProps, prevState) //組件更新完成,生命周期中可執行多次
unmounting
該方法將在組件正被被移除dom的時候觸發
componentWillUnmount() //組件將卸載,生命周期中只執行一次
error handing
2017-09-27 React 16 新加入
該方法將被調用當渲染過程,生命周期方法,或者任何子組件構造出錯的時候
componentDidCatch(error,info) //捕捉組件的邊界錯誤,生命周期中只執行一次
更改我們的index.js來驗證部分生命周期
import React from 'react'
class IndexSection extends React.Component{
constructor(props){
super(props);
this.state = {name:"IndexSection自身的state:name",age:"IndexSection自身的state:age"};
}
componentWillMount() {
console.log("componentWillMount");
}
componentDidMount() {
console.log("componentDidMount");
}
componentWillReceiveProps(nextProps) {
console.log("componentWillReceiveProps,nextProps:"+nextProps.name);
}
shouldComponentUpdate() {
console.log("shouldComponentUpdate");
return true; // 返回true/false
}
componentWillUpdate() {
console.log("componentWillUpdate");
}
componentDidUpdate() {
console.log("componentDidUpdate");
}
componentWillUnmount() {
console.log("componentWillUnmount");
}
render(){
// console.log(this.state);
return (
<section>
<h1>這是index.js里面的index_section組件</h1>
<h1>{this.props.name}</h1>
<h1>{this.state.age}</h1>
</section>
);
}
}
在這些生命周期方法里面都可以使用this.state和this.props來獲取組件的state和props,但是在shouldComponentUpdate和componentWillUpdate方法里面不能直接使用this.setState()方法來設置組件的state。
當調用setState時,實際上會執行enqueueSetState方法,并對partialState以及pending-StateQueue更新隊列進行合并操作,最終通過enqueueUpdate執行state更新
而performUpdateIfNecessary方法會獲取pendingElement, pendingStateQueue, pending-ForceUpdate,并調用receiveComponent和updateComponent方法進行組件更新
如果在shouldComponentUpdate或者componentWillUpdate方法中調用setState,此時this._pending-StateQueue != null,就會造成循環調用,使得瀏覽器內存占滿后崩潰。
事件系統
對于一些控件我們需要對其綁定事件,最常用的是點擊事件,在原生html里面我們對一個a標簽寫onclick標簽來綁定事件,在react里面使用onClick來綁定,當然還有其他的事件比如input框的onFocus,onBlur,onChange事件等,然后使用event.target來獲取事件對象的dom元素。下面的表格列出了部分事件
事件 | 事件名稱 |
---|---|
鼠標事件 | onClick,onContextMenu,onDoubleClick,onDrag,onDragEnd,onDragEnter |
... | onDragExit,onDragLeave,onDragOver,onDragStart,onDrop,onMouseDown, |
... | onMouseEnter,onMouseLeave,onMouseMove,onMouseOut,onMouseOver,onMouseUp |
鍵盤事件 | onKeyDown,onKeyPress,onKeyUp |
剪貼板事件 | onCopy,onCut,onPaste |
焦點事件 | onFocus,onBlur |
表單事件 | onChange,onInput,onSubmit |
觸控事件 | onTouchCancel,onTouchEnd onTouchMove,onTouchStart |
UI事件 | onScroll |
滾輪事件 | onWheel |
在index.js增加一個button,對其綁定點擊事件;增加一個select,對其綁定onChange事件
增加一個input事件,對其綁定onBlur事件。首先需要在constructor里面給添加的事件綁定this對象,再實現事件,最后在需要它的dom節點上綁定事件,當然,其他的方法中也可以使用this.函數名()來調用事件,如this.handleSubmit(data);
export default class Index extends React.Component{
constructor(props){
super(props);
this.handleClick = this.handleClick.bind(this);
this.handleBlur = this.handleBlur.bind(this);
this.handleChange = this.handleChange.bind(this);
}
handleClick(e){
console.log(e.target);
console.dir(e.target);
console.log("------------");
}
handleBlur(e){
console.log(e.target);
console.dir(e.target);
console.log(e.target.value);
console.log("------------");
}
handleChange(e){
console.log(e.target);
console.dir(e.target);
console.log(e.target.value);
console.log("------------");
}
render(){
return (
<div>
<h1>這是index.js</h1>
<button onClick={this.handleClick}>測試button點擊事件</button>
<div>
測試input框的onblur事件
<input type="text" onBlur={this.handleBlur} />
</div>
<div>
測試select的onchange事件
<select onChange={this.handleChange}>
<option value="opt1">選項1</option>
<option value="opt2">選項2</option>
<option value="opt3">選項3</option>
</select>
</div>
</div>
);
}
}
refs
refs是react中的一種屬性,可以在render方法中的虛擬dom節點添加ref屬性,refs的用途是獲取實例,可返回真實dom節點,修改index.js的代碼
export default class Index extends React.Component{
constructor(props){
super(props);
}
componentDidMount(){
console.log(this.refs.mybutton);
console.log(this.refs.mysection);
}
render(){
return (
<div>
<h1>這是index.js</h1>
<button ref="mybutton">測試button點擊事件</button>
<IndexSection ref="mysection"/>
</div>
);
}
}
可見,如果我們直接在html節點上添加ref屬性,通過this.refs.ref名即可獲得真實的dom節點;如果是在我們自己的組件上添加ref屬性,通過this.refs.ref名獲得的是虛擬dom節點,這樣就可以調用組件里面的方法。修改index.js
import React from 'react'
class IndexSection extends React.Component{
constructor(props){
super(props);
this.state = {name:"IndexSection自身的state:name",age:"IndexSection自身的state:age"};
this.testlog = this.testlog.bind(this);
}
testlog(){
console.log("使用ref調用子組件的方法");
}
...
}
export default class Index extends React.Component{
constructor(props){
super(props);
}
componentDidMount(){
console.log(this.refs.mybutton);
this.refs.mysection.testlog();
}
...
}
父子通信
父->子
父組件傳遞props給子組件 這里就不測試了
子->父
父組件使用props傳遞回調函數給子組件
修改index.js
import React from 'react'
class IndexSection extends React.Component{
constructor(props){
super(props);
this.state = {name:"IndexSection自身的state:name",age:"IndexSection自身的state:age"};
}
componentDidMount(){
this.props.test("子組件掛載完成");
}
...
}
export default class Index extends React.Component{
constructor(props){
super(props);
this.mymethod = this.mymethod.bind(this);
}
mymethod(e){
console.log("子組件調用了父組件的方法,傳遞參數值:"+e);
}
render(){
return (
<div>
<h1>這是index.js</h1>
<button ref="mybutton">測試button點擊事件</button>
<IndexSection test={this.mymethod}/>
</div>
);
}
}
此處注意constructor的綁定this對象和父組件給子組件設置回調函數props的花括號和子組件調用函數的this.props調用
子->子
父組件做通信橋梁使子組件能互相調用對方的回調函數
我們測試點擊IndexSection中的button修改IndexSectionA中button的文字,在index.js創建IndexSectionA組件,并創建setButtonText方法,父組件寫一個中間函數passtext,父組件給IndexSection組件傳遞中間函數passtext,給IndexSectionA設置ref屬性,并在passtext里面調用IndexSectionA的setButtonText方法。
index.js代碼如下
import React from 'react'
class IndexSection extends React.Component{
constructor(props){
super(props);
this.handleClick = this.handleClick.bind(this);
}
handleClick(){
this.props.settext("你的button文字被我修改了");
}
render(){
return (
<section>
<button onClick={this.handleClick}>IndexSection的按鈕,點擊我修改IndexSectionA的button文字</button>
</section>
);
}
}
class IndexSectionA extends React.Component{
constructor(props){
super(props);
this.state = {buttontext:"IndexSectionA的按鈕文字"}
}
setButtonText(text){
this.setState({buttontext:text});
}
render(){
return (
<section>
<button>{this.state.buttontext}</button>
</section>
);
}
}
export default class Index extends React.Component{
constructor(props){
super(props);
this.passmethod = this.passmethod.bind(this);
}
passmethod(e){
console.log("父組件充當通信橋梁,收到參數為:"+e);
this.refs.sectiona.setButtonText(e);
}
render(){
return (
<div>
<h1>這是index.js</h1>
<IndexSection settext={this.passmethod}/>
<hr/>
<IndexSectionA ref="sectiona"/>
<hr/>
</div>
);
}
}
網絡請求
作為一個網頁應用肯定需要請求網絡數據,本教程使用axios請求網絡,使用quertstring將對象序列化為字符串傳輸,首先使用npm安裝axios和querystring
npm install axios querystring -save
在app目錄下新建util文件夾,新建axios工具axios.js
import axios from 'axios'
import querystring from 'querystring';
export function axiosPost(url, params , callback ,errorcallback) {
let config = {
'headers':{'Content-Type': 'application/x-www-form-urlencoded'},
}
axios.post(url, querystring.stringify(params))
.then(result=>callback(result))
.catch(e => {console.log("Oops, error", e);if(errorcallback != null){errorcallback(e);}});
}
export function axiosGet(url, callback ,errorcallback){
let data = {
'headers':{'Content-Type': 'application/x-www-form-urlencoded'}
}
axios.get(url, data)
.then(result=>callback(result))
.catch(e => {console.log("Oops, error", e);if(errorcallback != null){errorcallback(e);}});
}
axios.js封裝了兩個函數,axiosGet和axiosPost,callback為請求成功回調,errorcallbak為請求失敗回調(可不傳)。
webpack-dev-server代理
在調試的時候我們有時需要使用網絡接口,使用axios請求數據則會遇到跨域問題,這時可在webpack-dev-server配置代理,修改webpack.config.js,這里我們配置中國天氣網接口的代理,順便測試使用上面的axios工具,北京天氣接口地址為:http://www.weather.com.cn/data/cityinfo/101010100.html 則找到webpack.config.js里面的devServer節點,添加proxy規則
proxy: {
'/data/*': {
target: 'http://www.weather.com.cn/',
secure: false,
changeOrigin: true
}
}
第2行的"/data/*"代表 localhost:3000/data/ 的請求會代理到target配置的網址,保存后重啟項目。在index.js引入axios工具,并在Index組件的componentDidMount函數下面測試使用axios請求北京天氣
import {axiosGet} from '../util/axios'
componentDidMount(){
axiosGet("/data/cityinfo/101010100.html",function(result){
console.log(result);
});
}
瀏覽器打開app首頁,F12進入調試工具,查看輸出的結果。
這里axios請求成功的回調帶回result參數,里面的data為接口返回的結果,status為http請求狀態碼
網絡請求一般在組件componentDidMount函數里面發起,獲取后設置為組件的state
react-router4路由
對react-router4的詳細講解請看我的另一篇文章React-Router v4簡單入門教程
我們之前都在學習react的基本使用,只在一個頁面也就是index上面練習,但是我們的應用肯定不只是一個頁面的,接下來我們使用react-router4作為前端路由編寫真正的SPA應用,建議開始之前大概瀏覽一下上面提到的講解文章。
首先安裝react-router-dom
npm install react-router-dom -save
在app文件夾創建router文件夾,在里面新建router.js,編寫路由配置
import React from 'react';
import {BrowserRouter,Route,Switch } from 'react-router-dom'
import Index from '../components/index.js'
export default class AppRouter extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<BrowserRouter>
<Switch>
<Route path="/" component={Index}></Route>
</Switch>
</BrowserRouter>
)
}
}
改造main.js,引入路由配置
import React from 'react';
import ReactDOM from 'react-dom';
import AppRouter from './router/router'; //路由配置
ReactDOM.render(
<AppRouter/>,
document.getElementById('app')
);
重啟項目,瀏覽器刷新后,index是不是又出來了?
接下來編寫一個新的頁面,在components文件夾下新建subpage.js
import React from 'react'
export default class SubPage extends React.Component{
constructor(props){
super(props);
}
render(){
return (
<div>
<h1>這是subpage.js。為subpage頁面</h1>
</div>
);
}
}
修改路由配置router.js
import React from 'react';
import {BrowserRouter,Route,Switch } from 'react-router-dom'
import Index from '../components/index.js'
import SubPage from '../components/subpage.js'
export default class AppRouter extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<BrowserRouter>
<Switch>
<Route exact path="/" component={Index}></Route>
<Route path="/subpage" component={SubPage}></Route>
</Switch>
</BrowserRouter>
)
}
}
刷新瀏覽器,在3000端口后面輸入"/subpage",觀察現象
出404錯誤?這是怎么回事?
我們的router配置確實是正確的,這時候就要考慮是否是webpack-dev-server的問題,果然,是因為webpack配置有問題。原文鏈接
果斷修改webpak.config.js,在devServer中添加historyApiFallback: true
devServer: {
inline: true,
historyApiFallback: true,
port: 3000
},
重啟項目再刷新瀏覽器
問題解決
我們想實現路徑參數避免search(a.html?param=..)出現,比如 /article?id=100 -> /article/100
更改我們的路由配置router.js
import React from 'react';
import {BrowserRouter,Route,Switch } from 'react-router-dom'
import Index from '../components/index.js'
import SubPage from '../components/subpage.js'
const Article = () =>(
<Switch>
<Route exact path="/article" component={SubPage}></Route>
<Route path="/article/:id" component={SubPage}></Route>
</Switch>
)
export default class AppRouter extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<BrowserRouter>
<Switch>
<Route exact path="/" component={Index}></Route>
<Route path="/article" component={Article}></Route>
</Switch>
</BrowserRouter>
)
}
}
修改subpage.js驗證參數是否傳到
render(){
return (
<div>
<h1>
這是subpage.js。為article頁面
{this.props.match.params.id != null ? ",id為"+this.props.match.params.id:null}
</h1>
</div>
);
}
這里BrowserRouter里面的<Route path="/article" component={Article}></Route>
匹配到的是所有以 /article 開頭的路徑,即/article和/article/:id ,渲染Article組件;在Article組件中配置了兩個Route,第一條是/article,但是前面有exact參數,說明只有 /article 路徑才能匹配到,第二條是/article/:id,/article/... 才能匹配到,SubPage組件里面使用this.props.match.params獲取params 對象,就可以拿到傳過來的id值。
引入css文件
由于我們使用webpack打包,css資源最終也會被打包嵌入到生成的js中,這時需要css的loader去幫我們處理css文件,一般處理css需要style-loader和css-loader,如果你打算使用less或sass的話,你可能需要安裝其他的loader來處理。首先我們安裝這兩個loader:npm install style-loader css-loader --save-dev
,然后修改webpack.config.js,找到module節點下的rule節點,添加如下代碼
{
test: /\.css$/,
use: [
'style-loader',
'css-loader',
],
}
test后面是一個正則表達式,代表匹配的文件為以.css結尾的文件使用style-loader和css-loader
之后我們在app目錄下創建文件夾style,用于存放css文件,并新建main.css
h1{
color:red;
font-size: 30px;
text-decoration: underline;
}
在index.js頭部引入該css:import '../style/main.css'
,查看瀏覽器頁面變化
這里需要說明的是,當在使用class屬性設置樣式的時候,在react里面,標簽不可以使用class來設置樣式,而是應該使用className來代替,如<div className="myclass">className來代替class</div>
。
使用webpack打包
看到這里,如果你一直跟著敲代碼到這里的話,你的app應該是有一個index頁面,一個article頁面,并且是引入了css樣式的,你可以接著編寫出其他的頁面,也可以跟著我學習如何進行打包。之前的代碼都是以dev模式運行在webpack-dev-server上,調試信息都會輸出在瀏覽器的控制臺,并且代碼沒有壓縮,整個js很大,我們需要對app進行打包。
首先在根目錄創建webpack.config.dist.js,可是我們已經有webpack.config.js了,為什么還需要創建一個呢?我們可以在webpack.config.dist.js里面配置發布版本的配置,而原來的webpack.config.js為調試版本的配置,所以不妨把webpack.config.js改名為webpack.config.dev.js,這樣還需要修改package.json文件下的scripts節點,添加start和build指令
"start": "webpack-dev-server --devtool eval --progress --colors --content-base build --config ./webpack.config.dev.js"
"build": "webpack -p --config ./webpack.config.dev.js"
新建webpack.config.dev.js
var path = require('path');
var webpack = require('webpack');
module.exports = {
entry: [path.resolve(__dirname, './app/main.js')],
output: {
path: path.resolve(__dirname, './build'),
filename: 'bundle.js',
publicPath:'/'
},
module: {
rules: [
{
test: /\.js?$/,
exclude: /(node_modules|bower_components)/,
loader: 'babel-loader',
},
{
test: /\.css$/,
use: [
'style-loader',
'css-loader',
],
}
],
},
plugins: [
//移除打包后的警告
new webpack.DefinePlugin({
"process.env": {
NODE_ENV: JSON.stringify("production")
}
}),
new webpack.optimize.ModuleConcatenationPlugin(),
]
};
保存之后,在終端輸入npm run build,打包好的js文件就放在build文件夾下了,現在生成的js從原來的600多kb壓縮為了170多kb,當然還可以壓縮的更小,比如提取公共模塊和按需加載。
nginx上部署
生成好后,我們就可以將build文件夾的index.html和bundle.js部署到服務器上了,這里我在centos虛擬機部署,這里部署的app當做靜態資源文件,我們先在centos虛擬機安裝nginx,由于是centos7 64位,先下載rpm包
wget http://nginx.org/packages/centos/7/x86_64/RPMS/nginx-1.12.2-1.el7_4.ngx.x86_64.rpm
然后安裝nginxsudo yum install nginx-1.12.2-1.el7_4.ngx.x86_64.rpm
啟動nginx服務 sudo service nginx start
打開瀏覽器輸入localhost,welcome to nginx!
之后配置nginx.conf,nginx配置文件夾在/etc/nginx下面,修改nginx.conf
user root;
worker_processes 1;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
#tcp_nopush on;
keepalive_timeout 65;
#gzip on;
server {
listen 80;
server_name localhost;
location / {
try_files $uri $uri/ /index.html;
root /home/shane/develope/static;
index index.html index.htm;
}
}
}
然后把build文件夾里面的index.html和bundle.js拷貝到虛擬機目錄的對應位置,即nginx配置的 location下的root對應的目錄,之后重啟nginx或reload,重啟吧...sudo service nginx restart
重要的一步。。。如果你也是centos7的話請先關閉SELinux,否則nginx沒有權限讀取文件,直接sudo setenforce 0
暫時關閉SELinux,然后訪問localhost:80 查看是否出現頁面