1 Функция, которую необходимо реализовать
Когда мы используем React для разработки проектов, это в основном одностраничное приложение, и без роутинга нам не обойтись. Маршрутизация кажется загадочной, когда мы просто моделируем ее основные функции, мы обнаруживаем, что это то же самое. В этой статье будет подробно рассказаноreact-router-dom
изHashRouter
основная логика реализации.
Функции, реализованные в данной работе, в основном включают в себя:
HashRouter
Route
Link
MenuLink
Switch
Redirect
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Вы можете попробовать вручную.
использованная литература: