16、React系列之--React 路由

版權聲明:本文為博主原創文章,未經博主允許不得轉載。

PS:轉載請注明出處
作者:TigerChain
地址:http://www.lxweimin.com/p/b55cf53e633a
本文出自 TigerChain簡書

React 教程系列

教程簡介

  • 1、閱讀對象

本篇教程適合初學者,老鳥直接略過,如果有誤,歡迎指出,謝謝。

一、什么是路由 ?

路由是什么我們可能不太理解,但是我說一個東西我們一定知道,就是"路由器",路由器的功能用一句話概括就是:數據從一個網絡到另一個網絡就是靠路由來完成的[當然路由器的功能不僅僅于此]。

我們說的程序開發中的路由不是指路由器和網絡協議中的路由,但是基本思想是一樣的。而路由又可以分為前端路由和后端路由。

我們來看一個路由的簡易圖吧,有了這個圖,大家對路由就有一個大致的了解了。

router.png

1、后端路由

舉個栗子,分配一個站點,服務器地址是: http://192.168.1.200:8080
,在這個網站中提供了三個界面,分別是:

http://192.168.1.200:8080/index.html
http://192.168.1.200:8080/about/aboutus.html
http://192.168.1.200:8080/feedback.html

當我們在瀏覽器中敲入 http://192.168.1.200:8080/index.html 來訪問頁面時,web 服務器接收到這個請求,然后把 /index.html 解析出來,然后找到 index.html 并展示出來,這就是路由分發,路由的分發是通過路由來完成的。

2、前端路由

雖然前端路由和后端路由在實現技術上差別,但是原理都 TM 的一樣。在 H5 的 history Api 之前,前端的路由功能都是使用通過 hash「散列值得」 來實現的。 hash 能兼容低版本的瀏覽器。比如:

http://192.168.1.200:8080/#/index.html
http://192.168.1.200:8080/#/about/aboutus.html
http://192.168.1.200:8080/#/feedback.html

由于 web 服務不會解析 # 后面的東西,可是 js 是可以拿到 # 后面的東西的,有一個方法就是 window.location.hash 來讀取,通過這個方法來匹配不同的功能上。

PS 我們進一步來說,舉個例子,有一個地址為:

http://www.xxx.com/path/a/b/c.html?key1=Tiger && key2=Chain && key3=fuck#/path/d/e.html
  • 1、我們來把這個地址解析一下:
http:協議
www.xxx.com:域名
/path/a/b/c.html:路徑,即服務器上的資源
?key1=Tiger && key2=Chain && key3=fuck:這個很好理解 Get 請求的參數
#/path/d/e.html:hash 也叫散列值,也叫錨點

上面的 hash 是和瀏覽器交互的,其它的都是和服務器進行交互的。

  • 2、hash 的改變,不會導致瀏覽器的刷新,我們來驗證一下。

先看我們要完成的效果:

customrouter.gif

我們看到了 hash 的改變不會導致瀏覽器的刷新,并且我們使用原生的 JS 定義了一個簡單的 SPA 「單頁應用」。

  • 3、源碼
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title> HashDemo </title>
</head>
<body>

<h3>我是 Hash 的一個 Demo</h3>
<hr />
<a href="#hash1">#hash1</a>
<a href="#hash2">#hash2</a>
<a href="#hash3">#hash3</a>
<a href="#hash4">#hash4</a>

<p/>
<div id = "show-hash-result" style="color:blue">
點擊上面鏈接,并觀察瀏覽器
</div>



<h4>自定義一個簡單的單面路由頁</h4>
<div id="nav">
<ul>
    <li><a href="#/index.html">首頁</a></li>
    <li><a href="#/server">服務</a></li>
    <li><a href="#/mine">我的</a></li>
</ul>
</div>
<div id="result"></div>


<style>

#nav {
  margin: 0;
  border: 0;
    height: 40px;
    width: 300px;
    border-top: #060 2px solid;
    margin-top: 10px;
    border-bottom: #060 2px solid;
    background-color: #690;
}

#nav ul {
  margin: 0;
  border: 0;
  list-style: none;
  line-height: 40px;
}

#nav li {
    display: block;
    float: left;
}

#nav a {
    display: block;
    color: #fff;
    text-decoration: none;
    padding: 0 20px;
}

#nav a:hover {
    background-color: #060;
}
</style>


<script type="text/javascript">
window.addEventListener("hashchange", function(){
  //變化后輸出當前地址欄中的值
  document.getElementById("show-hash-result").innerHTML = location.hash;

  console.log(window.location.hash) ;
});

</script>

<script type="text/javascript">
  //自定義一個路由規則
  function CustomRouter(){
    this.routes = {};
    this.curUrl = '';

    this.route = function(path, callback){
        this.routes[path] = callback || function(){};
    };

    this.refresh = function(){
        this.curUrl = location.hash.slice(1) || '/';
        if(this.curUrl.indexOf('/')!=-1){ //這里粗略的把 hash 過濾掉
            this.routes[this.curUrl]();
        }

    };

    this.init = function(){
        window.addEventListener('load', this.refresh.bind(this), false);
        window.addEventListener('hashchange', this.refresh.bind(this), false);
    }
  }

  //使用路由規則
  var R = new CustomRouter();
  R.init();
  var res = document.getElementById('result');

  R.route('/hash1',function () {
    document.getElementById("show-hash-result").innerHTML = location.hash;
  })

  R.route('/index.html', function() {
    res.style.height='150px';
    res.style.width='300px';
     res.style.background = 'green';
     res.innerHTML = '<html>我是首頁</html>';

  });
  R.route('/server', function() {
    res.style.height='150px';
    res.style.width='300px';
     res.style.background = 'orange';
     res.innerHTML = '我是服務頁面';
  });
  R.route('/mine', function() {
     res.style.background = 'red';
     res.style.height='150px';
     res.style.width='300px';
     res.innerHTML = '我的界面';
  });

</script>

</body>
</html>

代碼沒有整理和抽取,感興趣的可以再深層次的去改 「改到你滿意為止」。

  • h5 的 history

window 的 history 提供了對瀏覽器歷史記錄的訪問功能,并且它暴露了一些方法和屬性,讓你在歷史記錄中自由的前進和后退,并且在 H5 中還可以操作歷史記錄中的數據。

history 的 API 如下:

interface History {
    readonly attribute long length;
    readonly attribute any state;
    void go(optional long delta);
    void back();
    void forward();
    //h5 引進以下兩個方法
    void pushState(any data, DOMString title, optional DOMString? url = null);
    void replaceState(any data, DOMString title, optional DOMString? url = null);
    };
  • 1、back():在歷史記錄是后退
history.back() ;
  • 2、forward():在歷史記錄中前進
history.forward();
  • 3、go():移動到指定的歷史記錄點
history.go(-1)
  • 4、length:為 history 的屬性,顯示 history 的長度

關于 h5 的 history 推薦看這里,詳細的講解了 history,非常值得的看。

這里重點說 h5 的 pushState,完全代替 hash 并且更優雅。

廢話不多說,直接上效果圖

h5history.gif

以上我們實現了一個非常簡單的 SPA ,我們可以看到我們使用 histoy pushState 和 onpopstate 實現和上面 hash 一樣的功能。

源碼

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title> H5 HistoryDemo </title>
</head>
<body>

  <ul>
    <li><a onclick="home()">首頁</a></li>
    <li><a onclick="about()">關于</a></li>
    <li><a onclick="mine()">我的</a></li>
  </ul>

  <div id="showContent" style="height:250px;width:200px;background:green">home</div>

<script>

function home() {

history.pushState({name:'home',id:1}, null, "?page=home");

showCard("home");
}


function about() {
history.pushState({
  id:2,
  name:"about"
},null,"?page=about") ;

showCard("about");
}


function mine() {

history.pushState({
  id:3,
  name:"mine"
},null,"?name=chen&age=30") ;

showCard("mine");
}

function showCard(name) {
   document.getElementById("showContent").innerHTML = name;
}

//點擊返回鍵盤的時候顯示歷史
window.onpopstate = function (event) {
  var content = "";
  if(event.state) {
    content = event.state.name;
  }
  showCard(content);
}

</script>
</body>
</html>

PS:基于 h5 history 實現的路由和最初的路由基本上一致。

http://192.168.1.200:8080/index
http://192.168.1.200:8080/about/aboutus
http://192.168.1.200:8080/feedback

從性能上來說,后端路由每次向 server 發起一個請求,server 要解析響應,就會有延時,而前端路由只是變換了一下路徑,沒有網絡延時這一說,所以性能「用戶體驗」是大大的提升了。

經過以上我們對路由有了一個大體的理解,我們接下來說我們的重點 React 的路由功能。

二、React 路由

React 官方沒有給出一個明確的組件,推薦使用三方的一個叫 React Router 的組件。「當然我們不使用 React Router 也可以完成路由功能,比如傳統的 hash 功能,沒有問題,但是用了它就非常方便和好用」。

我們都是知道 React 玩的就是組件化,所以 React Router 也是一個組件。

1、廢話不多說,我們直接寫一個簡單的 SPA Demo 感受一下

效果如下:


reactrouterspa.gif

從圖可以看到我們使用 React router 實現一個簡單的 SPA 應用。如果大家細心看了前面的知識點,這個沒有什么好說的。

2、下面我們擼碼,通過代碼來直觀的感受一下 「這次我使用的是 windows 開發,不過不影響,你可以直接在 mac 開發」。

  • 1、老步驟,我們在指定的目錄下創建一個叫 reactrouterdemo 的文件夾

比如:

D:\study\react-study\lesson03\reactrouter\reactrouterdemo
  • 2、在命令行中 win 中是 cmd ,mac 下是 ter

進入到 reactrouterdemo 目錄中創建項目

yarn init // 一路回車即可
yarn add react react-dom webpack webpack-dev-server babel-core babel-loader babel-preset-es2015 babel-preset-react babel-preset-stage-0 --dev //安裝依賴的插件,不清楚,可以看 webpack 這一節

  • 3、在 reactrouterdemo 中新建 app 和 public 文件夾和 .babelrc 和 webpack.config.js,在 public 下面新建 index.html,在 app 中新建 main.js 如下所示:
reactrouerfolder.png

然后每個文件中對應的內容

.babelrc

# .babelrc

{
  "presets": ["react", "es2015","stage-0"]
}

webpack.config.js

# webpack.config.js

module.exports = {
  entry:  __dirname + "/app/main.js",//已多次提及的唯一入口文件
  output: {
    path: __dirname + "/public",//打包后的文件存放的地方
    filename: "bundle.js"http://打包后輸出文件的文件名
  },
  devServer:{
  contentBase: "./public",//本地服務器所加載的頁面所在的目錄
//  colors: true,//終端中輸出結果為彩色
  historyApiFallback: true,//不跳轉
  inline: true//實時刷新
},
//新增加部分
 module:{
   loaders:[
   //babel配置
   {
     test:/\.js$/,
     exclude: /node_modules/,
     loader: 'babel-loader'
   }
 ]
 }
}

index.html

# index.html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>ReactRouter Demo</title>
</head>
<body>
  <div id="container"></div>
  <script src="bundle.js"></script>
</body>
</html>

這沒有什么好說的,如果看過 webpack 等章節,我們就很快的創建這些東西。

接下來我們安裝 react-router

yarn add react-router --dev
# main.js

import React from 'react' ;
import ReactDOM from 'react-dom' ;

import { Router, Route, Link ,hashHistory} from 'react-router';

/**
 * 定義 Home 組件
 * @type {String}
 */
class Home extends React.Component{
  render(){
    return(<div>
      Home
    </div>) ;
  }
}

/**
 * 定義 About 子頁面組件
 * @type {String}
 */
class About extends React.Component{
  render(){
    return(
      <div>About</div>
    ) ;
  }
}

 class App extends React.Component {
  render() {
    return (
      <div>
        <h1>App</h1>
        <ul>
          <li><Link to="/home">首頁</Link></li>
          <li><Link to="/about">關于我</Link></li>
        </ul>
      </div>
    );
  }
}

ReactDOM.render((
  <Router>
    <Route  path="/" component={App}/>
    <Route path="/home" component={Home} />
    <Route path="/about" component={About} />
  </Router>
), document.getElementById('container'));

最后配置 package.json 文件的腳本,添加下面一句。

package.json

 "scripts": {
    "start": "webpack-dev-server --progress --port 8888"
  }

好了,到此為止我們基本上寫完一個簡單的 SPA 頁面了,讓我們來驗證一下吧,我們在命令行中輸入 yarn start,一切 ok ,我們打開瀏覽器輸入 localhost:8888,如果沒有什么大問題,你毛也看不到,這個時候不要慌,打開 chrome 調試工具 「別給我說你沒有使用 chorme 調試 web 頁面,如果沒有自己去面面壁」。結果如下

reacterror.png

What The Fuck ,什么鬼嗎,按照文檔 「這個翻譯文檔過時了」來的居然出錯了,好吧,解決問題,把上面框出來的問題到 Google 上一搜,答案在這里,來吧上一張圖

reactrouterv4pro.png

大體意思是說,如果你使用的 react-router v4 版本 「上一個穩定版本是 2.8.1」,那么就要使用 react-router-dom,并且這是 v4 版本中的更新 「 v4 中有很多更新」。啥是react-router-dom 呢,你只要知道一般我們前端就用這個包來進行WEB開發了,這一篇文章詳細的介紹了,也就是使用 react-router-dom 完全可以替代 react-router 。

PS: 如果你的項目中已經在使用react-router之前的版本,那一定要慎重的更新,因為新的版本是一次非常大的改動,如果你要更新,工作量并不小。關于 React-router 2.8 左右的版本可以看阮一峰的:http://www.ruanyifeng.com/blog/2016/05/react_router.html?utm_source=tool.lu 文章,非常好。

  • 4、安裝 react-router-dom 組件

上面說了,react-router-dom 可以迭代 react-router ,那么我們先把 react-router 卸載了,然后安裝 react-router-dom

yarn remove react-router //卸載 react-router
yarn add react-router-dom --dev

然后修改 main.js,這里只修改一句話:

將 mport { Router, Route, Link } from 'react-router'; 修改為 

import {
  BrowserRouter as Router,
  Route,
  Link
} from 'react-router-dom';

然后看結果,還是出不來,看 chorme 的輸出臺,這下變了,不是上面的錯誤了,而是

routeronechild.png

大概意思就是 <Router> 標簽只能有一個子元素,這好辦,加一個 div 不就搞定了。

修改地方是 :

adddiv2router.png

然后再看結果,神奇般出來了我們開頭的效果,真不容易呀。

總結:我們在開發 web 頁面的時候就使用 react-router-dom 來代替以前的 react-router 就可以了。他們的用法稍微有不同:

  • react-router-dom 不能嵌套使用 「我沒有試出來」。
  • react-router-dom <Router> 結點只能有一個子元素,類似于 React 的 render 方法。

以上我們就簡單的開發一個 React-router 的 SPA ,我們對 React-router v4 也有了一個大概的解,下面我們具體說說 React-router
v4 的一些用法吧。

到此為止,我們對 react router 有一個大體的認識,下一節們再詳細的說說 react-router v4 的一些用法。

三、react-router v4 介紹

1、react-router v4 沒有嵌套之用法了

2、傳遞參數「url 傳參」

經過上面的了解我們知道,React-router v4 中,我們在 Router 組件中可以寫任意的標簽,但是只能有一個根標簽。

url 傳參,我們使用通配符 :id ,下面我們結合代碼一起看看。

  • 1、在上面代碼的基礎上我們修改 main.js
# main.js

import React from 'react' ;
import ReactDOM from 'react-dom' ;

import {
  BrowserRouter as Router,
  Route,
  HashRouter,
  Link
} from 'react-router-dom';

/**
 * 定義 Home 組件
 * @type {String}
 */
class Home extends React.Component{
  render(){
    return(<div>
      Home
    </div>) ;
  }
}

/**
 * 定義 About 子頁面組件
 * @type {String}
 */
class About extends React.Component{
  render(){
    return(
      <div>About</div>
    ) ;
  }
}

 class App extends React.Component {
  render() {
    return (
      <div>
        <h1>App</h1>
        <ul>
          <li><Link to="/home">首頁</Link></li>
          <li><Link to="/about">關于我</Link></li>
          <li><Link to="/haha">haha</Link></li>
        </ul>
      </div>
    );
  }
}

// 在 react-router v4.0 中獲取 接收參數使用 this.props.match.params.屬性名字
class Haha extends React.Component{
  render(){
    return(
      <div>
      <h3> ID: {this.props.match.params.id}</h3>

      match.url:  {this.props.match.url}

      </div>
    ) ;

  }
}

// 無狀態的組件
// const Haha = ({ match }) => (
//   <div>
//     <h3>ID: {match.params.id}</h3>
//   </div>
// )


ReactDOM.render((
  <HashRouter>
    <div>
    <Route   path="/" component={App}/>
    <Route path="/home" component={Home} />
    <Route path="/about" component={About} />

    <Route path="/:id" component={Haha}/>
  </div>
  </HashRouter>
), document.getElementById('container'));


  • 2、直接運行看效果
react-router-url-param.gif

通過上圖我們可以看到 :id 匹配的是 home,about,haha,我們再看 chorme 調試工具,很清楚的看到 li 標簽中的 link 其實就是一個 a 標簽,to 就相當于 href 屬性。

細習的朋友可能發現了,我這里使用 HashRouter 代替了 Router,那么這個有什么作用呢,答案就是在上面的運行結果中,我們看到點擊首頁等鏈接的時候,地址欄中自動加了一個 # ,也就說 HashRouter 是前面的說的 hash 的方式實現路由。

如何取得 id 的參數呢,我們通過

his.props.match.params.id

來取得,這里的 id 就是你 :id 中的 id ,名字可以自己改。

四、React-router 實例

1、本實例我們基于 ant design 來仿一下 ant design「以下簡稱 antd」 的網站「體驗一下 spa 應用中 react-router的應用,本次選用 react-router@2.8.1 來開發」

對 ant design 不了解的可以看看官方:https://ant.design/index-cn,它是一個 UI 設計語言類似于 bootstrap ,并且它和 react 無縫結合

首先我們來看一下 ant design 的官網界面如下:

ant_design.gif

再來看看,我們仿的界面:

fant_design.gif

怎么樣,大體上還是很像的吧,當然我只是為了演示 react-router 在 spa 應用中的應用,仿的肯定和原生沒有百分百一樣「css 如果要做的好,就要花費大量的時間和精力,本人的 css 能力還是很薄弱的」

2、好我廢話不多,我們直接開始擼代碼吧「在 mac 環境下,win 下是一樣的」

  • 1、在指定目錄新建 antddemo 目錄,并且使用 yarn 初始化項目
mkdir antddemo
cd antddemo
yarn init 

然后一路回車即可

  • 2、在 antddemo 中 分別新建 src 文件夾,.babel 文件 ,webpack.config.js 文件等,目錄結構如下:
├── index.html
├── package.json
├── src
│   ├── imgs
│   ├── js
│   │   ├── component
│   │   └── index.js
│   └── styles
├── webpack.config.js
├── yarn-error.log
└── yarn.lock

PS: index.js 就我們的入口 js 文件,imgs 用來存放本地圖片,styles 用來放 css 文件,component 用來存放編寫的 react 組件的

  • 3、安裝所需要依賴庫
yarn add react react-dom //回車,繼續安裝
yarn add babel-core babel-loader babel-preset-es2015 babel-preset-react babel-preset-stage-0 webpack webpack-dev-server style-loader url-loader css-loader antd react-hot-loader react-router@2.8.1 --dev

然后回車沒有什么問題即就顯示安裝成功,我這里一口氣所需要的依賴都安裝好了,你也可以分別來安裝。

  • 4、配置 .babelrc
{
  "presets":["react","stage-0","es2015"],
  "plugins": [
    ["import", { "libraryName": "antd", "style": "css" }]
  ]
}

其中的 plugin 是配置 antd 的,具體可以看官網,這里大概說一下,根據前面的經驗我們知道一個 css 樣式是可以被 import 進來的,如果我們添加了 css-loader 和 style-loader 的話,如果 antd 想被 import 引入來使用的話,我們還需要安裝一個插件 babel-plugin-import「也是官司方推薦的」,具體可以看官方的按需要加載這一小結:https://ant.design/docs/react/introduce-cn

下面我們安裝 babel-plugin-import

yarn add babel-plugin-import --dev

ps:.babelrc 里面的 plugin 就是 配置 babel-plugin-import 這玩意的

  • 5、下面看一下 webpack.config.js 配置
# webpack.config.js

module.exports = {
  entry:  __dirname + "/src/js/index.js",
  output: {
    path: __dirname + "/src/",  //打包后文件地址
    publicPath:"/src/",   //命令行模式下,一定要配置output.publicPath來指定編譯后的包(bundle)的訪問位置.
  filename: "bundle.js"  //打包后文件
  },
  module: {
    loaders: [
      //babel配置
    {
      test:/\.js$/,
      exclude: /node_modules/,
      loader: 'babel-loader'
    },
  // 為了不和 antd css 樣式沖突,我們
     {
    test: /\.css$/,
    loader: 'css-loader?sourceMap&modules&localIdentName=[local]___[hash:base64:5]!!',
    exclude: /node_modules/
     },
  // style-loader css-loader 配置
   {
      test: /\.css$/,
      loader: 'style-loader!css-loader'
   },
   //加載本地圖片 配置 url-loader
    {test:/\.(png|jpg)$/,loader:"url-loader?limit=8192&name=img/[name][hash:8].[ext]"
    }

    ]
  },

  devServer:{
    hot:true,
    historyApiFallback: true,//不跳轉
    inline: true//實時刷新
  }
}

PS:這里要注意一點,由我們安裝了 css-loader 和 antd ,我們需要對 antd 單獨配置一下,就是把 node_modules 下的文件都 exclude 掉,不要讓它走 css-modules,否則 css-loader 會把 antd 的 css 樣式全部沖掉「你引入的 antd 樣式死活都加載不出來,切記、切記、切記」,具體可以看這里:https://github.com/ant-design/ant-design/issues/3442

  • 6、組件的劃分

以上我們只是搭建了一個架子,那么既然 react 牛 b 的地方就是組件化,我們就把 antd 網頁劃分一下組件吧,由 antd 官網我們可以看到,上面底部和底部是不變的,我們可以分別抽出一個組件來,具體組件劃分如下:

ant_component.png

由上圖我們看到 antd 大體來說就分為這四個組件。并用只有內容區域是變化的,其它組件不變

  • 7、index.html
# index.html
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
  <link rel="stylesheet" href="src/styles/pc.css">
  <link rel="stylesheet" href="src/styles/main.css">
  <link rel="stylesheet" href="src/styles/common.css">
</head>
<body>
  <div id="container"></div>
  <script type="text/javascript" src="./src/bundle.js">

  </script>
</body>
</html>

和我們以前的 index.html 基本上沒有什么區別,只不過我們引入幾個 css 樣式而已

  • 8、看主 js --> index.js
# index.js

import React,{Component} from 'react' ;
import ReactDOM from 'react-dom' ;

// 這里我們使用 react-router 2.8.1
import {hashHistory,Router,Route,IndexRoute,Link} from 'react-router' ;

//引入 pc 主界面組件
import PCIndex from './component/pc_index.js' ;

import AntdofReact from './component/antdofreact.js' ;
// 引入快速上手組件
import QuickStart from './component/quick_start.js' ;
//引入項目實踐組件
import ProjectPractice from './component/projectpractice.js' ;
//引入在 react 中使用組件
import UseInReact from './component/useinreact.js' ;

//引入自定義主題組件
import CustomTheme from './component/customtheme.js' ;
//引入更新日志組件
import UpDateLog from './component/updatelog.js' ;


class Main extends React.Component {
  render(){
    return(
      // 定義路由
      <Router  history={hashHistory}>
        <Route path="/" component={PCIndex}>
          <IndexRoute  component={AntdofReact}></IndexRoute>
          <Route path="react/getting-started-cn" component={QuickStart}></Route>
          <Route path="react/practical-projects-cn" component={ProjectPractice}></Route>
          <Route path="react/use-with-create-react-app-cn" component={UseInReact}></Route>
          <Route path="react/customize-theme-cn" component={CustomTheme}></Route>
          <Route path="react/changelog-cn" component={UpDateLog}></Route>
        </Route>
      </Router>

    ) ;
  }
}

ReactDOM.render(
  <Main />,document.getElementById('container')
) ;

在這里我們路由規則都定定出來了。

  • 9、我們看看 pc_index.js 就像是一個盒子,組裝頭部、底部、和內容
import React, { Component, PropTypes } from 'react';

// 導入頭部組件
import PCHeader from './pc_header.js' ;
//導入主體內容組件
import PCMAIN from './pc_main.js' ;
//導入底部組件
import PCFooter from './pc_footer.js' ;

//首頁 包含公共的頭部和底部
export default class PCIndex extends Component {
  constructor(props) {
    super(props);
  }

  render() {
    //取得 PCIndex中的子組件  下句就相當于 const children = this.props.children
    const {children} = this.props
    return (
      <div>
        <PCHeader />
        <PCMAIN maincontent={children}/>
        <PCFooter />
      </div>
    );
  }
}

PCIndex.propTypes = {
};

我們拿一個圖來直觀的看一下 pc_index.js 組件的組合作用

ant_component-2.png
  • 10、我們再來看看 pc_main.js 組件
import React, { Component, PropTypes } from 'react';

import PCMenu from './pc_menu.js' ;

// 內容組件
export default class PCMain extends Component {
  constructor(props) {
    super(props);
  }


  render() {
     const {maincontent} = this.props;
    return (
        <main className="main">
          {/* 菜單 */}
         <div className="menu">
            <PCMenu />
         </div>
          {/* 內容 */}
         <div className="content">
            {maincontent}
         </div>

        </main>
    );
  }
}

PCMain.propTypes = {
};

pc_main.js 組件也就是組合了菜單組件,和內容「也可以定義成一個組件,自己試試吧,React 中一切皆組件」

此時變成這樣了,如下圖所示:

ant_component-3.png

好了,以上就是核心代碼,如果一個個 js 去說沒有什么意義,浪費時間,可以自行下載 demo 體驗一下

PS:后記,我們仿 antd 網站使用是的 React-router v2.8 來做的「讓大家體驗一下"曾今"(當然現在也很流行)流行的路由」,后面抽出時間,改成 React-router v4 版本。

demo地址:https://github.com/tigerchain/react-lesson/tree/master/lesson03/13-reactrouter

據說每個勤奮、努力、想成為牛 b 的人會點一個喜歡的

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容