使用哈希或 URL 进行单页应用程序路由

2025-06-07

使用哈希或 URL 进行单页应用程序路由

前端面试中最常问的代码问题之一是“你能创建一个带有路由的单页应用程序,而无需框架吗?”在本教程中,我将向您展示如何使用哈希或 URL 方法为单页应用程序创建自定义路由系统……无需框架。

本教程将向您展示如何使用原生 JavaScript 构建单页应用。我将向您展示如何以易于使用且可在任何项目中复制的格式实现客户端双向路由(哈希或 URL)。

在 YouTube 上观看

文件夹结构

我们使用的是基本的 HTML 结构。您可以随意设置文件,但为了本教程的目的,您可以复制我下面的内容。

index.html
/templates
   404.html
   index.html
   about.html
   contact.html
/js/
   router.js
Enter fullscreen mode Exit fullscreen mode

让我们创建 HTML

我们将创建一个基本的 HTML 文档作为主页。此页面包含一个导航部分和一个内容部分。您可以根据需要构建导航部分,但请注意,这些<nav></nav>标签用于 URL 路由,因此如果您要使用 URL 路由方法,导航部分必须位于这些标签内。

<!DOCTYPE html>
<html lang="en">
   <head>
      <meta charset="UTF-8">
      <meta http-equiv="X-UA-Compatible" content="IE=edge">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title></title>
   </head>
   <body>
      <nav>
      </nav>
      <div id="content"></div>
   </body>
</html>
Enter fullscreen mode Exit fullscreen mode

创建 JS 文件

在结束标记之前</body>,您需要将此引用添加到您上面创建的 JS 文件中。

<script src="/js/router.js"></script>

选项一:URL 路由

首先,我们将讨论如何使用URL 路由来实现这一点。这意味着你的链接将看起来像这样/about。这是 URL 的典型外观。哈希值方法用于#拆分页面。我将在下文中进一步讨论这一点。

用例:网站

此选项更有利于 SEO,并且更加用户友好。

注意:使用此方法有一些缺点。您需要配置 Web 服务器来为 SPA 路由路径提供 index.html 文件。您可以在服务器级别执行此操作,但如果您使用的是 VS Code LIVE SERVER 之类的服务,则无法执行此操作。这意味着,如果您直接导航到 /about,服务器将无法渲染该文件,因为它需要先加载 index.html 脚本。您可以修改 .htaccess 文件来实现这一点。

添加 HTML 导航

<nav></nav>在 index.html 文件的标签之间添加以下内容。

<a href="/">Home</a>
<a href="/about">About</a>
<a href="/contact">Contact</a>
Enter fullscreen mode Exit fullscreen mode

在 HTML 中添加导航链接

现在,让我们开始编写 JS。首先,我们要让<nav></nav>标签中的任何链接都使用我们的路由。

// create document click that watches the nav links only
document.addEventListener("click", (e) => {
    const { target } = e;
    if (!target.matches("nav a")) {
        return;
    }
    e.preventDefault();
    route();
});
Enter fullscreen mode Exit fullscreen mode

创建路线

每个路由都会有一个与之关联的对象数组。这将告诉脚本 URL 引用是什么,以及要使用的模板、标题和描述。

const routes = {
    404: {
        template: "/templates/404.html",
        title: "404",
        description: "Page not found",
    },
    "/": {
        template: "/templates/index.html",
        title: "Home",
        description: "This is the home page",
    },
    "/about": {
        template: "/templates/about.html",
        title: "About Us",
        description: "This is the about page",
    },
    "/contact": {
        template: "/templates/contact.html",
        title: "Contact Us",
        description: "This is the contact page",
    },
};
Enter fullscreen mode Exit fullscreen mode

创建一个监视 URL 并调用 urlLocationHandler 的函数

const route = (event) => {
    event = event || window.event; // get window.event if event argument not provided
    event.preventDefault();
    // window.history.pushState(state, unused, target link);
    window.history.pushState({}, "", event.target.href);
    locationHandler();
};
Enter fullscreen mode Exit fullscreen mode

创建一个处理 URL 位置的函数

const locationHandler = async () => {
    const location = window.location.pathname; // get the url path
    // if the path length is 0, set it to primary page route
    if (location.length == 0) {
        location = "/";
    }
    // get the route object from the urlRoutes object
    const route = routes[location] || routes["404"];
    // get the html from the template
    const html = await fetch(route.template).then((response) => response.text());
    // set the content of the content div to the html
    document.getElementById("content").innerHTML = html;
    // set the title of the document to the title of the route
    document.title = route.title;
    // set the description of the document to the description of the route
    document
        .querySelector('meta[name="description"]')
        .setAttribute("content", route.description);
};
Enter fullscreen mode Exit fullscreen mode

完成剧本

最后,我们需要在页面首次加载时调用该函数,否则主页将无法显示,除非点击它。我们还需要添加一个 URL 变化的监听器,以便脚本知道何时显示新内容。

// add an event listener to the window that watches for url changes
window.onpopstate = locationHandler;
// call the urlLocationHandler function to handle the initial url
window.route = route;
// call the urlLocationHandler function to handle the initial url
locationHandler();
Enter fullscreen mode Exit fullscreen mode

选项二:哈希路由

如果您使用哈希方法,请用以下代码替换 router.js 文件的内容。

现在,我们来看看第二种方案。如果你使用框架,哈希路由#about会更常见,但如果你从头开始创建它,其负面的 SEO 优势可能会让你望而却步。这意味着你的链接看起来会不像上面提到的典型 URL 方法。对于某些用户来说,这种 URL 类型可能并非最佳选择,因为它与用户习惯的 URL 有很大不同。否则,代码与 URL 方法非常相似……甚至更短。

用例:应用程序、登陆页面

注意:使用此方法有一些缺点。单哈希可能不是 SEO 的最佳途径,并且对于某些用户来说也可能不寻常,这可能会导致他们不使用该网站。

添加 HTML 导航

<nav></nav>在 index.html 文件的标签之间添加以下内容。

<a href="/">Home</a>
<a href="#about">About</a>
<a href="#contact">Contact</a>
Enter fullscreen mode Exit fullscreen mode

创建路线

哈希路由看起来与上面的 URL 路由非常相似。您可以重复使用脚本的这一部分。区别主要在于路由链接键的定义方式。

const routes = {
    404: {
        template: "/templates/404.html",
        title: "404",
        description: "Page not found",
    },
    "/": {
        template: "/templates/index.html",
        title: "Home",
        description: "This is the home page",
    },
    about: {
        template: "/templates/about.html",
        title: "About Us",
        description: "This is the about page",
    },
    contact: {
        template: "/templates/contact.html",
        title: "Contact Us",
        description: "This is the contact page",
    },
};
Enter fullscreen mode Exit fullscreen mode

创建一个处理 URL 位置的函数

const locationHandler = async () => {
    // get the url path, replace hash with empty string
    var location = window.location.hash.replace("#", "");
    // if the path length is 0, set it to primary page route
    if (location.length == 0) {
        location = "/";
    }
    // get the route object from the routes object
    const route = routes[location] || routes["404"];
    // get the html from the template
    const html = await fetch(route.template).then((response) => response.text());
    // set the content of the content div to the html
    document.getElementById("content").innerHTML = html;
    // set the title of the document to the title of the route
    document.title = route.title;
    // set the description of the document to the description of the route
    document
        .querySelector('meta[name="description"]')
        .setAttribute("content", route.description);
};
Enter fullscreen mode Exit fullscreen mode

完成剧本

再次强调,我们需要在页面首次加载时调用该函数,否则主页将无法显示,除非用户点击它。我们还需要添加一个监听器来监测哈希值的变化,以便脚本知道何时显示新内容。

// create a function that watches the hash and calls the urlLocationHandler
window.addEventListener("hashchange", locationHandler);
// call the urlLocationHandler to load the page
locationHandler();
Enter fullscreen mode Exit fullscreen mode

结论

虽然有很多方法可以做到这一点,但你需要了解以下两种方法,才能成为更优秀的前端开发者。一旦你掌握了这些方法,你就可以继续学习 React 或 Vue 框架了。希望这些简单却至关重要的学习方法能帮助你通过文章开头那道令人头疼的面试题。祝你好运!

阅读有关DevDrawer 的更多文章

文章来源:https://dev.to/thedevdrawer/single-page-application-routing-using-hash-or-url-9jh
PREV
如何设置 Web 服务器 AWS GenAI LIVE!
NEXT
十大必知 JavaScript 函数!十大必知 JavaScript 函数