当前位置:首页 > 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);
  }
}

实现动态路由匹配

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

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);
    }
  }
}

实现嵌套路由

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

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组件系统集成。

自己实现react router

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

电脑如何安装react

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

如何降低react版本

如何降低react版本

降低 React 项目版本的步骤 检查当前 React 版本 运行以下命令查看项目中安装的 React 当前版本: npm list react 或 yarn list react 修改…

react如何验证

react如何验证

表单验证方法 在React中验证表单数据通常使用以下几种方式: 内置HTML5验证 利用HTML5原生表单验证属性如required、pattern等,结合form.noValidate属性禁用浏览…

如何提高react

如何提高react

优化性能 使用React.memo对组件进行记忆化处理,避免不必要的重新渲染。对于类组件,可以使用PureComponent来达到类似效果。 利用useMemo缓存计算结果,避免重复计算。对于函数或…

如何调试react

如何调试react

调试 React 应用的方法 使用 React Developer Tools 安装浏览器扩展(Chrome/Firefox),通过组件树查看组件状态、props 和 hooks。支持实时编辑 pro…

react 如何引用slider

react 如何引用slider

使用 React 实现 Slider 组件 在 React 中实现 Slider 功能可以通过原生 HTML 的 <input type="range"> 或第三方库(如 react-sl…