You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何使用原生JavaScript实现Angular 2路由?

Implementing Angular 2-Style Routing with Vanilla JavaScript

Got it, let's break down how to implement Angular 2-style routing using plain vanilla JavaScript—no TypeScript, no frameworks, just good old JS. This approach covers the core routing features you'd expect from Angular 2: route configuration, dynamic route parameters, component rendering, and navigation handling.

1. Define Your Route Configuration

First, set up a route config similar to Angular's Routes array. Each route will have a path, a "component" (a function that returns HTML or manipulates the DOM), and optionally a flag for exact matches.

const routes = [
  { path: '', component: HomeComponent, exact: true },
  { path: 'about', component: AboutComponent },
  { path: 'users/:id', component: UserDetailComponent },
  { path: '**', component: NotFoundComponent } // Catch-all for 404
];

// Example "components" - these are just functions that return HTML
function HomeComponent() {
  return `<h1>Home Page</h1><p>Welcome to the vanilla JS routing demo!</p>`;
}

function AboutComponent() {
  return `<h1>About Us</h1><p>We're building routing from scratch!</p>`;
}

function UserDetailComponent(params) {
  return `<h1>User ${params.id}</h1><p>Viewing details for user ID: ${params.id}</p>`;
}

function NotFoundComponent() {
  return `<h1>404 - Page Not Found</h1>`;
}

2. Build the Core Router Class

This class will handle URL parsing, route matching, component rendering, and navigation events—just like Angular's Router service.

class Router {
  constructor(routes, outletId) {
    this.routes = routes;
    this.outlet = document.getElementById(outletId);
    this.init();
  }

  // Initialize router: listen for popstate (back/forward) and initial render
  init() {
    window.addEventListener('popstate', () => this.handleRouteChange());
    this.handleRouteChange();
  }

  // Get the current path from the hash (hash mode, no server config needed)
  getCurrentPath() {
    return window.location.hash.slice(1) || '';
  }

  // Match the current path to a route in the config
  matchRoute(path) {
    for (const route of this.routes) {
      // Convert route path to regex for dynamic parameters (e.g., /users/:id → ^\/users\/(\w+)$)
      const routeRegex = new RegExp(`^${route.path.replace(/:(\w+)/g, '($1)').replace(/\//g, '\\/')}$`);
      const match = path.match(routeRegex);

      if (match) {
        // Extract dynamic parameters
        const params = {};
        const paramNames = route.path.match(/:(\w+)/g) || [];
        paramNames.forEach((name, index) => {
          params[name.slice(1)] = match[index + 1];
        });

        return { ...route, params };
      }

      // Handle exact matches for root path
      if (route.exact && path === route.path) {
        return { ...route, params: {} };
      }
    }

    // Fallback to catch-all route
    return this.routes.find(route => route.path === '**');
  }

  // Render the matched component into the outlet
  renderComponent(route) {
    if (!this.outlet) return;
    this.outlet.innerHTML = route.component(route.params);
  }

  // Handle route changes (manual navigation or popstate)
  handleRouteChange() {
    const path = this.getCurrentPath();
    const matchedRoute = this.matchRoute(path);
    this.renderComponent(matchedRoute);
  }

  // Programmatic navigation (like router.navigate())
  navigate(path) {
    window.location.hash = path;
  }
}

Create links that work like Angular's routerLink directive. We'll use a custom data-router-link attribute and listen for clicks to trigger navigation.

<!-- Navigation bar -->
<nav>
  <a data-router-link="/">Home</a>
  <a data-router-link="/about">About</a>
  <a data-router-link="/users/123">User 123</a>
  <a data-router-link="/non-existent">404 Test</a>
</nav>

<!-- Route outlet (where components render) -->
<div id="router-outlet"></div>

Add JavaScript to handle these links:

// Initialize the router with our routes and outlet ID
const router = new Router(routes, 'router-outlet');

// Handle router link clicks
document.addEventListener('click', (e) => {
  const routerLink = e.target.getAttribute('data-router-link');
  if (routerLink) {
    e.preventDefault();
    router.navigate(routerLink);
  }
});

4. Key Features Explained

  • Hash Mode: We're using window.location.hash to avoid needing server-side configuration (for HTML5 mode, you'd need to set up your server to redirect all requests to index.html).
  • Dynamic Parameters: The router uses regex to parse paths like /users/:id and extract the id parameter, passing it to the component function.
  • Exact Matches: The exact flag ensures the root path ('') only matches when the hash is empty, not every path that starts with /.
  • Programmatic Navigation: The navigate() method lets you trigger route changes from code, just like Angular's router.navigate().

5. Testing the Implementation

  1. Save all the code into an HTML file.
  2. Open it in a browser.
  3. Click the navigation links to see components render dynamically.
  4. Use the browser's back/forward buttons—they should work thanks to the popstate listener.
  5. Try visiting a non-existent path to see the 404 component.

内容的提问来源于stack exchange,提问作者Nav

火山引擎 最新活动