本次主要实现的是Hash路由,也就是监听/#/后面的hash值得变化。
使用过react的都知道,this.props上面有一个比较重要的属性location,match, history等,这一次我们实现里面的几个简单属性,用于完成路由,如下:
location: {pathname } history: { push} match: { url, path, params}
由于设计到父子组件传递,所有我们用到了context.
对于hash的改变我们可以在window注册hashchange事件。
HashRouter组件
import React, { Component } from "react";
import RouteContext from "./RouteContext";
export default class HashRouter extends Component {
constructor (props) {
super(props);
this.state = { location: {}, history: {}, match: {}};
this.handleHash = this.handleHash.bind(this);
}
handleHash () {
const hash = window.location.hash.slice(1); //获取#后面的路径
this.setState( (perProps, perState) => {
return {
...perState,
location: {
...perState.location,
pathname: hash //也就是pathname里面的值
},
history: {
...perState.history,
push: (event, pathname) => { //push函数很简单,就是改变当前window下面的hash
event.preventDefault();
window.location.hash = pathname;
}
}
}
})
}
componentDidMount () {
// window.location.hash = window.location.hash || "/";
this.handleHash();
window.addEventListener("hashchange", () => { //在window上注册hashchange事件
this.handleHash();
} )
}
render () {
return (
{ this.props.children }
)
}
}
Route组件
使用了pathtoregexp用正则来处理hash(比如这样的/a/b/:id)
import React, { Component } from "react";
import RouteContext from "./RouteContext";
import pathToRegexp from "path-to-regexp";
export default class Route extends Component {
constructor (props) {
super(props);
const { src } = this.props;
this.key = [];
this.regexp = pathToRegexp(src, this.key, { end: false }) //生成正则
this.key = this.key.map( (user) => (user.name) ); //获取:id :name这样的
}
render () {
const { src, component: Component } = this.props;
return (
{
(context) => {
const { pathname } = context.location;
let result;
if (pathname) result = pathname.match(this.regexp); //看是否匹配成功
if (result) {
const [url, ...values] = result; //如果成功那么就把match里面的一些属性生成,
const match = {
...context.match,
url,
path: src,
params: this.key.reduce((memo, v, index) => {
memo[v] = values[index];
return memo;
}, {})
}//返回component属性里面的组件
return
} else {
return null;
}
// if ( pathname && (pathname === src || pathname.startsWith(src))) return ;
// else return null;
}
}
)
}
}
Link组件
import React, { Component } from "react";
import RouteContext from "./RouteContext";
export default class Link extends Component {
render () {
return (
{
(context) => {
const hashPush = context.history.push; //简单就是一个a标签,然后就是利用history.push来跳转
return { hashPush(e, this.props.to)} } >{ this.props.children }
}
}
)
}
}
Switch组件
import React, { Component } from "react";
import RouteContext from "./RouteContext";
import pathToRegexp from "path-to-regexp";
export default class Switch extends Component {//作用匹配唯一一个路由
render () {
const children = this.props.children;
return (
{
(context) => {
const { pathname } = context.location;
for (let i = 0; i < children.length; i++) { //如果匹配到第一个就返回
let child = children[i];
const { src } = child.props;
const regexp = pathToRegexp(src, [], { end: false });
if (regexp.test(pathname)) return child;
}
}
}
)
}
}
差不多了,就可以实现一个简单的路由。
输入一个id,然后一个名字,提交后会存入localStorage,点击用户展示就显示所有人的ID,然后点击ID就会进入用户页面。