<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>
to
属性,为要跳转的路径, 标签里边可以写文本等内容import Route from './Route';
import HashRouter from './HashRouter';
import Link from './Link';
export { HashRouter, Route, Link };
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;
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;
这里把 正则匹配的那个单独抽出来了, 因为 下边还有组件要用到
import React, { Component } from 'react';
import Context from './Context';
import { isMatch } from './utils';
class Route extends Component {
static contextType = Context;
render() {
// // 拿到 这上边的属性
let { component: Component } = this.props;
if (isMatch(this.context, this.props)) {
return <Component />;
}
return null;
}
}
export default Route;
在这里统一处理 # 符号问题
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);
}
代码及效果演示