当前位置:首页 > React

自己实现react router

2026-01-26 21:05:19React

实现基本路由功能

创建一个简单的路由系统需要管理URL变化并渲染对应的组件。可以使用浏览器History API或hash模式。

class Router {
  constructor(routes) {
    this.routes = routes;
    this._loadInitialRoute();
    window.addEventListener('popstate', this._handlePopState.bind(this));
  }

  _loadInitialRoute() {
    const path = window.location.pathname;
    this._handleRouteChange(path);
  }

  _handlePopState() {
    const path = window.location.pathname;
    this._handleRouteChange(path);
  }

  _handleRouteChange(path) {
    const matchedRoute = this.routes.find(route => route.path === path);
    if (matchedRoute) {
      matchedRoute.component();
    } else {
      this.routes.find(route => route.path === '/404').component();
    }
  }

  navigate(path) {
    window.history.pushState({}, '', path);
    this._handleRouteChange(path);
  }
}

实现动态路由匹配

扩展基本路由功能以支持参数化路由和通配符。

自己实现react router

class Router {
  // ...原有代码...

  _matchRoute(path) {
    for (const route of this.routes) {
      const paramNames = [];
      const regexPath = route.path
        .replace(/:(\w+)/g, (_, paramName) => {
          paramNames.push(paramName);
          return '([^\\/]+)';
        })
        .replace(/\*/g, '.*');

      const routeRegex = new RegExp(`^${regexPath}$`);
      const match = path.match(routeRegex);

      if (match) {
        const params = {};
        paramNames.forEach((name, index) => {
          params[name] = match[index + 1];
        });
        return { route, params };
      }
    }
    return null;
  }

  _handleRouteChange(path) {
    const match = this._matchRoute(path);
    if (match) {
      match.route.component(match.params);
    } else {
      this.routes.find(route => route.path === '/404').component();
    }
  }
}

实现路由钩子

添加路由守卫功能,在导航前后执行特定逻辑。

class Router {
  constructor(routes) {
    this.routes = routes;
    this.beforeHooks = [];
    this.afterHooks = [];
    // ...其他初始化代码...
  }

  beforeEach(hook) {
    this.beforeHooks.push(hook);
  }

  afterEach(hook) {
    this.afterHooks.push(hook);
  }

  async navigate(path) {
    const currentPath = window.location.pathname;
    if (path === currentPath) return;

    for (const hook of this.beforeHooks) {
      const shouldContinue = await hook(currentPath, path);
      if (shouldContinue === false) return;
    }

    window.history.pushState({}, '', path);
    this._handleRouteChange(path);

    for (const hook of this.afterHooks) {
      hook(currentPath, path);
    }
  }
}

实现嵌套路由

支持子路由配置和嵌套视图渲染。

自己实现react router

class Router {
  // ...原有代码...

  _handleRouteChange(path, parentElement = null) {
    const match = this._matchRoute(path);
    if (!match) {
      this.routes.find(route => route.path === '/404').component();
      return;
    }

    const { route, params } = match;
    if (route.children) {
      const childPath = path.replace(route.path, '') || '/';
      const childMatch = this._matchNestedRoute(childPath, route.children);

      if (childMatch) {
        const element = document.createElement('div');
        route.component(element, params);
        this._handleRouteChange(childPath, element);
      }
    } else {
      route.component(parentElement, params);
    }
  }

  _matchNestedRoute(path, routes) {
    // 类似_matchRoute的实现,但针对子路由
  }
}

实现Link组件

创建声明式导航组件,避免全页面刷新。

class Link extends HTMLElement {
  constructor() {
    super();
    this.attachShadow({ mode: 'open' });
    this.addEventListener('click', this._handleClick.bind(this));
  }

  connectedCallback() {
    const href = this.getAttribute('href');
    const text = this.textContent;
    this.shadowRoot.innerHTML = `
      <style>
        a { text-decoration: none; color: inherit; }
      </style>
      <a href="${href}">${text}</a>
    `;
  }

  _handleClick(event) {
    event.preventDefault();
    const href = this.getAttribute('href');
    window.dispatchEvent(new CustomEvent('router:navigate', { detail: href }));
  }
}

customElements.define('router-link', Link);

集成到React

将自定义路由系统与React组件系统集成。

function withRouter(Component) {
  return function WrappedComponent(props) {
    const [currentPath, setCurrentPath] = useState(window.location.pathname);

    useEffect(() => {
      const handleNavigation = (event) => {
        setCurrentPath(event.detail);
      };

      window.addEventListener('router:navigate', handleNavigation);
      return () => {
        window.removeEventListener('router:navigate', handleNavigation);
      };
    }, []);

    return <Component {...props} currentPath={currentPath} />;
  };
}

function Route({ path, component: Component, currentPath }) {
  const router = useContext(RouterContext);
  const match = router._matchRoute(currentPath);

  if (match && match.route.path === path) {
    return <Component params={match.params} />;
  }
  return null;
}

这个实现涵盖了React Router的核心功能,包括基本路由、动态路由、路由守卫、嵌套路由和声明式导航。可以根据需要进一步扩展功能或优化性能。

标签: reactrouter
分享给朋友:

相关文章

react中monent如何获取日期

react中monent如何获取日期

使用 Moment.js 获取日期 在 React 项目中,可以通过 Moment.js 库轻松处理日期和时间。以下是几种常见的日期获取方法。 安装 Moment.js 确保项目中已安装 Momen…

电脑如何安装react

电脑如何安装react

安装 Node.js 和 npm React 依赖于 Node.js 和 npm(Node Package Manager)。从 Node.js 官网下载并安装最新稳定版本,安装完成后会自动包含 np…

如何手写一个react

如何手写一个react

手写一个简单的 React 创建一个基础的 React 实现需要理解其核心概念:虚拟 DOM、组件、状态管理和渲染。以下是一个简化版的 React 实现。 创建虚拟 DOM 虚拟 DOM 是真实…

如何改造react

如何改造react

改造 React 项目的关键方法 分析当前项目结构 通过评估现有组件、状态管理和依赖项,明确需要改进的部分。使用工具如 webpack-bundle-analyzer 识别性能瓶颈。 升级 Reac…

react如何部署

react如何部署

部署 React 应用的常见方法 使用静态服务器部署 React 应用在构建后会生成静态文件,可以直接通过静态服务器部署。常用的静态服务器包括 Nginx、Apache 等。 运行构建命令生成静态文…

react如何运行

react如何运行

运行React项目的步骤 安装Node.js 确保系统已安装Node.js(建议版本12以上),可从官网下载并安装。Node.js自带npm包管理器,用于后续依赖安装。 创建React项目 使用官方…