如何制做本身的原生 JavaScript 路由

@js_tut

翻译:疯狂的技术宅javascript

https://www.freecodecamp.org/...html

未经容许严禁转载前端

当你想到路由时,一般会想到相似 React 之类的库。但实际上,这些库和框架仍然使用 vanilla JavaScript。那么该怎么实现呢?java

我但愿这个“JavaScript 路由教程”可以帮你了解如何用原生 JS 写出本身的路由。程序员

简介

我遇到了不少出于各类缘由想要本身建立路由的人。既然你看到本文,那意味着你可能也是其中的一个!面试

最重要的是,使用 vanilla JS router 能够减小你对框架的依赖。正则表达式

只要你了解实现它所涉及的全部部分,就能够相对容易的在原生 JavaScript 中建立本身的路由。segmentfault

如下是制做本身的 JS router 时要了解的关键事项:后端

  1. 原生 JS 路由的关键是 location.pathname 属性。
  2. 侦听 “popstate ”事件以响应.pathname 的更改。每当在浏览器的地址栏中输入新的 URL,但咱们不想刷新页面时,就会发生这种状况,咱们只是想经过加载新内容来刷新视图。
  3. 你能够选择将路由存储在 routes[] 数组中。
  4. 必须用 JavaScript 正则表达式RegEx)才能解析 URL。
  5. 若是但愿将路由集成到本机浏览器体系结构中,那么对 historyhistory.pushState(JavaScript 的 History API)的基本了解相当重要。

首先,咱们将处理 History API。数组

JavaScript 的 History API

我看过不少没有提到 JavaScript History API 的 vanilla JS router 教程。太糟糕了,由于单击浏览器的“后退”和“前进”按钮与浏览历史记录中的 URL 导航有关。若是没有 History API,就没法谈论路由。

  1. history.back()history.go(-1) 相同,或者当用户在浏览器中单击 Back 按钮时。你能够用任何一种方法达到相同的效果。
  2. 当用户按下浏览器的 Forward 按钮时,将执行 history.forward(),它等效于 history.go(1)”。
  3. go().back()forward() 方法类似,不一样之处在于你能够指定浏览器历史记录栈中要前进或后退的步数。 。
  4. pushState() 会将新状态推送到 History API。
  5. .length 属性是会话历史记录中的元素数。
  6. .state 属性用于查找状态,而无需侦听“ popstate” 事件。

如今开始实现咱们本身的原生 JS 路由!

我将简单地对的 HTMLCSSJavaScript 进行注释。

基于 History API 的 Vanilla JS 路由设置

先让咱们仔细研究构建 URL 切换器所需的最少代码(而无需刷新页面),而后我会向你展现其的工做方式的 GIF 动图。

<html>
    <head>
        <title>Hello</title>
        <script type = "module">
            function select_tab(id) {
                // remove selected class from all buttons
                document.querySelectorAll(".route").forEach(item => item.classList.remove('selected'));
                // select clicked element (visually)
                document.querySelectorAll("#" + id).forEach(item => item.classList.add('selected'));
            }
            function load_content(id) {
                // Update text "Content loading for {id}..."
                // Of course, here you would do you content loading magic
                // Perhaps run Fetch API to update resources
                document.querySelector("#content").innerHTML = 'Content loading for /' + id + '...';
            }
            function push(event) {
                // Get id attribute of the box or button or link clicked
                let id = event.target.id;
                // Visually select the clicked button/tab/box
                select_tab(id);
                // Update Title in Window's Tab
                document.title = id;
                // Load content for this tab/page
                loadContent(id);
                // Finally push state change to the address bar
                window.history.pushState({id}, `${id}`, `/page/${id}`);
            }
            window.onload = event => {
                // Add history push() event when boxes are clicked
                window["home"].addEventListener("click", event => push(event))
                window["about"].addEventListener("click", event => push(event))
                window["gallery"].addEventListener("click", event => push(event))
                window["contact"].addEventListener("click", event => push(event))
                window["help"].addEventListener("click", event => push(event))
            }
            // Listen for PopStateEvent (Back or Forward buttons are clicked)
            window.addEventListener("popstate", event => {
                // Grab the history state id
                let stateId = event.state.id;
                // Show clicked id in console (just for fun)
                console.log("stateId = ", stateId);
                // Visually select the clicked button/tab/box
                select_tab(stateId);
                // Load content for this tab/page
                loadContent(id);
            });
        </script>
        <style>
            * { /* global font */
                font-family: Verdana;
                font-size: 18px;
            }
            #root { display: flex; flex-direction: row; }
            #content { display: flex;
                display: block;
                width: 800px;
                height: 250px;
                /* vertically centered text */
                line-height: 250px;
                border: 2px solid #555;
                margin: 32px;
                text-align: center;
            }
            .route {
                cursor: pointer;
                justify-content: center;
                width: 150px;
                height: 50px;
                /* vertically centered text */
                line-height: 50px;
                position: relative;
                border: 2px solid #555;
                background: white;
                text-align: center;
                margin: 16px;
            }
            .route.selected { background: yellow; }
        </style>
    </head>

    <body>

        <section id = "root">
            <section class = "route" id = "home">/home</section>
            <section class = "route" id = "about">/about</section>
            <section class = "route" id = "gallery">/gallery</section>
            <section class = "route" id = "contact">/contact</section>
            <section class = "route" id = "help">/help</section>
        </section>

        <main id = "content">Content loading...</main>
    
    </body>

</html>

核心是对的 window.history.pushState({id}, ${id}, /page/${id}); 调用;

第一个参数是状态的惟一 ID,第二个是“标签标题”文本,第三个参数是你但愿地址栏中要现实的路径。这就是使浏览器无需从新加载页面便可更改 URL 的缘由。

结果。如今,每次咱们单击按钮时,URL实际上都会在浏览器的地址栏中更改。内容框也会更新。

routing.gif

咱们的原生 JS 路由开始运行了。请注意,每次单击按钮时,history.pushState 被触发。咱们只需将存储在元素的 id 属性中的 clicked 元素的 id 传递给它便可:homeaboutgallery 等。它们应与你要导航到的实际页面一致。固然这不是存储页面名称的惟一方法,例如能够用 array [] 或其余任何方式。这就是本例中的操做方式。

固然咱们还须要从服务器加载有关该位置的布局和资源的内容。这取决于你的程序。能够是任何东西。

使“后退”和“前进”按钮起做用

经过使用 history.pushState,你将自动使 BackForward 按钮导航到上一个或下一个状态。这样作会产生 popstate事件。这是你必须再次更新视图的部分。 (第一次是咱们单击按钮时。)

可是因为该事件带有单击的 id,所以单击 BackForward 时很容易刷新视图并从新加载内容。

咱们在这里没有使用 React 或 Vue,所以在个人源代码中 load_content 将负责直接在 DOM 中更新视图。此区域可能填充了你的 API 加载的某些内容。因为这只是“前端”示例,所以我没法向你展现太多内容。但这就是它在客户端上的工做方式。

初始化服务器端的路由负载

将它们放在一块儿还须要再执行一个步骤。在个人例子中,只用了 router.html。当你第一次在 PWA 中加载此路由时,必须确保若是直接在地址栏中输入/page/home时,它能够工做。

到目前为止,咱们仅从前端更改了路由器地址。假定每次你导航到出如今路由按钮上的 URL 时,实际上都会从服务器单独加载该 URL。

所以你有责任确保/page/about 将路由器和页面的加载到应用程序的根视图中。它还应突出显示“current”按钮。

实施完毕后,你的路由就完成了。你如何选择从新加载 #content 元素中的内容彻底取决于你本身和你的后端设计。


本文首发微信公众号:前端先锋

欢迎扫描二维码关注公众号,天天都给你推送新鲜的前端技术文章

欢迎扫描二维码关注公众号,天天都给你推送新鲜的前端技术文章

欢迎继续阅读本专栏其它高赞文章:


相关文章
相关标签/搜索