原生Link組件用法
<Router>
<Link to='/'>Home</Link>
<Link to='/about'>About</Link>
<Link to='/mine'>Mine</Link>
<div>
<Route component={Home} path='/' exact></Route>
<Route component={About} path='/about'></Route>
<Route component={Mine} path='/mine'></Route>
</div>
</Router>
- 導出Link 組件, 該組件 接收一個
to
屬性,爲要跳轉的路徑, 標籤裏邊可以寫文本等內容
實現自己的Link 組件
- 入口文件先導出這個組件
import Route from './Route';
import HashRouter from './HashRouter';
import Link from './Link';
export { HashRouter, Route, Link };
- 創建Link.js
import React from 'react';
class Link extends React.Component {
render() {
// 拿到傳入的 to屬性對應的值, 拿到內部的子節點或文本
const { to, children } = this.props;
// 轉化成 a 標籤
return <a href={`#` + to}>{children}</a>;
}
}
export default Link;
改進Link 組件
- 現在使用的是 a 標籤的 默認錨點行爲進行跳轉的,把它改成 方法跳轉的
import React, { Component } from 'react';
import Context from './Context';
class Link extends Component {
static contextType = Context;
// 阻止默認行爲,進行事件跳轉
hashPush = (e, to) => {
e.preventDefault();
this.context.history.push(to);
};
render() {
const { to, children } = this.props;
return (
<a href={`#` + to} onClick={(e) => this.hashPush(e, to)}>
{children}
</a>
);
}
}
export default Link;
在 HashRouter文件上添加 跳轉方法
同時這裏處理一個問題, 就是初始化默認hash值的問題,讓它默認爲 #/, 不再去掉了,而是在 Route文件中處理
import React, { Component } from 'react';
import Context from './Context';
class HashRouter extends Component {
state = {
location: {
pathname: '#/', // 默認hash 值路徑
},
history: {
push(path) {
// 路徑跳轉方法
window.location.hash = '#' + path;
},
},
};
UNSAFE_componentWillMount() {
// 監聽hash 值的變化
window.addEventListener('hashchange', () => {
this.setState((state) => ({
...state,
location: {
pathname: window.location.hash || '#/',
},
}));
});
}
render() {
return (
<Context.Provider value={this.state}>
{this.props.children}
</Context.Provider>
);
}
}
export default HashRouter;
Route.js
這裏把 正則匹配的那個單獨抽出來了, 因爲 下邊還有組件要用到
import React, { Component } from 'react';
import Context from './Context';
import { isMatch } from './utils';
class Route extends Component {
static contextType = Context;
render() {
// // 拿到 <Route component={Home} path='/' exact></Route> 這上邊的屬性
let { component: Component } = this.props;
if (isMatch(this.context, this.props)) {
return <Component />;
}
return null;
}
}
export default Route;
utils.js
在這裏統一處理 # 符號問題
import { pathToRegexp } from 'path-to-regexp';
/**
* @returns 匹配的結果 true | false
* @param {*} context 上下文
* @param {*} component props
*/
export function isMatch(context, props) {
const { path, exact = false, to } = props;
// 拿到上下文中的 hash 值
let { pathname } = context.location;
// 截取掉 # 號
pathname = pathname.slice(1);
// 轉成正則
// path || to 如果是Route 組件上都是path, 但Redirect 上是 to 屬性,這裏需要處理
let regexp = pathToRegexp(path || to, [], { end: exact });
return pathname.match(regexp);
}