1 Функция, которую необходимо реализовать
Когда мы используем React для разработки проектов, это в основном одностраничное приложение, и без роутинга нам не обойтись. Маршрутизация кажется загадочной, когда мы просто моделируем ее основные функции, мы обнаруживаем, что это то же самое. В этой статье будет подробно рассказаноreact-router-domизHashRouterосновная логика реализации.
Функции, реализованные в данной работе, в основном включают в себя:
HashRouterRouteLinkMenuLinkSwitchRedirect
2 Реализованная логика
Не будем сначала говорить о том, как пишется код, а сначала посмотрим на картинку.HashRouterЧто за чертовщина:
-
HashRouterЭто большой контейнер, он управляет тем, как он рендерится, так чем он управляется?Вы можете догадаться из его названия, то естьwindow.location.hash. - когда
HashRouterКогда он начнет рендеринг, он займет свое собственноеpathnameАтрибуты такие же, как и в его животеRouteизpathСовпадение, если оно совпадает, оно будет отображатьсяRouteизcomponentсоответствующий компонент. -
LinkКак переключать маршруты?Это очень просто, достаточно пройтиthis.props.history.push(path)изменитьHashRouterсерединаpathnameсвойства, которые, в свою очередь, приводятRoute们Повторите рендеринг, снова сопоставьте наш маршрут и, наконец, поменяйте маршруты.
Введена простая логика, теперь давайте посмотрим, как она реализована, как показано на следующем рисунке:
-
HashRouterявляется унаследованнымReact.Componentкласс, в этом классеstateвключатьlocation, мониторингhashизменения на дискеRouteповторный рендеринг компонента, а такжеhistoryАтрибут, вы можете переключить маршрутизацию страницы. - Функции, которые будут реализованы в этой статье, включают
Route,Link,MenuLink,Switch,Redirect,вRouteОснова – это ядро,MenuLinkИ некоторые рендеры с определенной логикой находятся вRouteреализовано на основе . -
RouteСуществует три типа переменных, которые можно получить в компоненте, в том числеcomponent,render,children,вrender,childrenвсе функции,renderзаключается в отображении элементов в соответствии с определенной логикой,childrenиспользуется для рендерингаMenuLink, обе функции получают текущий маршрутprops, возвращаемое значение функции — это отображаемый элемент. -
SwitchРеализованная логика заключается в возвратеchildrenсредний каблукhashПервый "дочерний элемент", который соответствует.
3 Особая логика кода
(1) HashRouter
HashRouterБудуwindow.loacation.hashсо своимstateкрючок, изменив свой собственныйstateУскоряет повторный рендеринг страницы.
import React, {Component} from 'react';
import PropTypes from 'prop-types';
export default class HashRouter extends Component {
constructor() {
super();
this.state = {
location: {
pathname: window.location.hash.slice(1) || '/', // 当前页面的hash值
state: {} //保存的状态
}
};
}
// 定义上下文的变量类型
static childContextTypes = {
location: PropTypes.object,
history: PropTypes.object
}
// 定义上下文的变量
getChildContext() {
return {
location: this.state.location,
history: {
push: (path) => { // 就是更新 window.hash值
if (typeof path === 'object') {
let {pathname, state} = path;
this.setState({
location: {
...this.state.location,
state // {from: '/profile'}
}
}, () => {
window.location.hash = pathname;
})
} else {
window.location.hash = path;
}
}
}
}
}
render() {
return this.props.children; // 渲染页面元素
}
componentDidMount() {
window.location.hash = window.location.hash.slice(1) || '/';
// 监听window的hash的变化,驱动页面的重新刷新
window.addEventListener('hashchange', () => {
this.setState({
location: {
...this.state.location,
pathname: window.location.hash.slice(1) || '/'
}
});
})
}
}
(2) Route
RouteОсновная логика рендеринга заключается в преобразовании собственногоpathи текущая страницаhashВыполняется сопоставление, и соответствующий элемент отображается, если он соответствует, и ничего не отображается, если он не соответствует.
import React, {Component} from 'react';
import PropTypes from 'prop-types';
import pathToRegexp from 'path-to-regexp'
export default class Route extends Component {
// 定义上下文context的类型
static contextTypes = {
location: PropTypes.object,
history: PropTypes.object
}
render() {
// 解构传入Route的props
let {path, component: Component, render, children} = this.props;
// 解构上下文的属性
let {location, history} = this.context;
let props = {
location,
history
};
// 将传入Route的path和当前的hash进行匹配
let keys = [];
let regexp = pathToRegexp(path, keys, {end: false});
keys = keys.map(key => key.name);
let result = location.pathname.match(regexp);
if (result) { // 匹配上了
let [url, ...values] = result;
props.match = {
path,
url,
params: keys.reduce((memo, key, index) => { // 获取匹配到的参数
memo[key] = values[index];
return memo;
}, {})
};
if (Component) { // 普通的Route
return <Component {...props} />;
} else if (render) { // 特定逻辑的渲染
return render(props);
} else if (children) { // MenuLink的渲染
return children(props);
} else {
return null;
}
} else { // 没有匹配上
if (children) { // MenuLink的渲染
return children(props);
} else {
return null;
}
}
}
}
(3) Redirect
RedirectПросто сделай одно, измениHashRouterизstate, драйвер выполняет повторную визуализацию.
import React, {Component} from 'react';
import PropTypes from 'prop-types';
export default class Redirect extends Component {
// 定义上下文context的Type
static contextTypes = {
history: PropTypes.object
}
componentDidMount() {
// 跳转到目标路由
this.context.history.push(this.props.to);
}
render() {
return null;
}
}
(4) MenuLink
import React, {Component} from 'react';
import Route from "./Route";
import Link from './Link'
export default ({to, children}) => {
// 如果匹配到了,就给当前组件一个激活状态的className
return <Route path={to} children={props => (
<li className={props.match ? "active" : ""}>
<Link to={to}>{children}</Link>
</li>
)
}/>
}
(5) Link
LinkОн должен отображаться в теге, затем давать событие щелчка и изменять его при нажатии.HashRouterсостояние, которое управляет повторным рендерингом.
import React, {Component} from 'react';
import PropTypes from 'prop-types';
export default class Link extends Component {
static contextTypes = {
history: PropTypes.object
}
render() {
return (
<a onClick={() => this.context.history.push(this.props.to)}>{this.props.children}</a>
)
}
}
(6) Switch
import React, {Component} from 'react';
import PropTypes from 'prop-types';
import pathToRegexp from 'path-to-regexp';
export default class Switch extends Component {
static contextTypes = {
location: PropTypes.object
}
render() {
let {pathname} = this.context.location;
let children = this.props.children;
for (let i = 0, l = children.length; i < l; i++) {
let child = children[i];
let path = child.props.path;
if (pathToRegexp(path, [], {end: false}).test(pathname)) {
// 将匹配到的第一个元素返回
return child;
}
}
return null
}
}
4 написать в конце
Хорошо, эти функции были введены, вы правы?HashRouterВы понимаете принцип? В этой статье публикуется только часть кода, если он вам нужен, прочтите его.demoВы можете попробовать вручную.
использованная литература: