單頁Web應用(single page web application,SPA),就是隻有一張Web頁面的應用。是隻加載單個HTML頁面,並在用戶與應用程序交互時動態更新該頁面的Web應用程序。而React
、Vue
就是構建單頁應用的前端主流框架。css
對比 | 單頁面應用 | 多頁面應用 |
---|---|---|
組成 | 一個外殼頁面和多個頁面組件(片斷)構成 | 多個完整的頁面組成 |
資源(css,js) | 可共用,只須要在外殼部分加載 | 須要時向服務器請求,資源獨立 |
首次加載 | 首屏加載慢 | 每次加載區別不大 |
用戶體驗 | 用戶體驗好,內容改變不須要從新加載整個頁面,後續服務器壓力小 | 頁面加載慢,每次加載須要對服務器進行請求 |
轉場動畫 | 能夠實現 | 沒法實現 |
搜索引擎優化(SEO) | 效果較差,可經過SSR服務端渲染,成本較高 | 效果好 |
經過監聽路由的變化,去匹配路由所對應的組件,並將組件映射到路由上。當路由改變時框架能有效地更新並正確地渲染組件。前端
這裏我介紹HashRouter的實現原理、過程react
React Router中有三類組件:git
對應路由的兩種模式hash和historygithub
控制路徑對應的顯示組件web
路由切換,跳轉正則表達式
以一個demo爲例api
export default class App extends Component {
render() {
return (
<HashRouter>
<Route path="/home" component={Home}></Route>
<Route path="/user" component={User}></Route>
</HashRouter>
)
}
}
ReactDOM.render(<App />,
document.getElementById('root')
);
複製代碼
這裏Route組件得到了對應的路徑和所要展現的組件,並嵌套在Router組件中。瀏覽器
首先咱們要知道BOM的一些特性bash
BOM
是一套操做瀏覽器的API,而window是BOM中的一個頂級的對象,咱們能夠經過this.props打印掛載在window下的一些信息,以掘金爲例
而HashRouter的實現就依賴於這些Api,咱們能夠經過window.location.href
拿到咱們所在的url值。
固然經過這個就能夠了嗎?等等,Route做爲HashRouter的嵌套組件是怎麼拿到url路徑去匹配path的呢?
這裏React-Router採用了React16.3版本提出的api React.createContext
能夠解決父組件向子組件、孫子孫子...傳值,爲多組件嵌套數據傳遞提供解決方案。
//咱們經過一個context.js方法引入這個api
import React from 'react';
let { Provider, Consumer } = React.createContext()
export { Provider, Consumer }
複製代碼
而HashRouter便充當了這個生產者的角色,經過window.addEventListener('hashChange',callback)
監聽hash值的變化,並傳遞給其嵌套的組件。
具體代碼以下:
import React, { Component } from 'react';
import { Provider } from './context'
// 該組件下Api提供給子組件使用
class HashRouter extends Component {
constructor() {
super()
this.state = {
location: {
pathname: window.location.hash.slice(1) || '/'
}
}
}
// url路徑變化 改變location
componentDidMount() {
window.location.hash = window.location.hash || '/'
window.addEventListener('hashchange', () => {
this.setState({
location: {
...this.state.location,
pathname: window.location.hash.slice(1) || '/'
}
}, () => console.log(this.state.location))
})
}
render() {
let value = {
location: this.state.location
}
return (
<Provider value={value}>
{
this.props.children
}
</Provider>
);
}
}
export default HashRouter;
複製代碼
Route組件則充當的消費者的角色,經過一個回調接收到HashRouter傳遞過來的url路徑值,並進行後面的匹配渲染組件
import React, { Component } from 'react';
import { Consumer } from './context'
const { pathToRegexp } = require("path-to-regexp");
class Route extends Component {
render() {
return (
<Consumer>
{
state => {
console.log(state)
let {path, component: Component} = this.props
let pathname = state.location.pathname
let reg = pathToRegexp(path, [], {end: false})
// 判斷當前path是否包含pathname
if(pathname.match(reg)) {
return <Component></Component>
}
return null
}
}
</Consumer>
);
}
}
export default Route;
複製代碼
因爲官方實現的正則表達式較爲複雜,這裏我藉助了path-to-regexp
這個插件去進行正則匹配的處理。
實現效果:
本次只是簡單的模擬了下HashRouter的實現過程,對React-Router的實現原理也有了必定的認識。最後,學習的過程,重在總結,樂在分享,具體的代碼你們能夠看個人github 歡迎你們留言和我交流分享😀。