前端路由实现的关键知识点
哈希路由(Hash Routing)
哈希路由使用URL中的哈希部分(即#
符号后面的部分)来控制页面内容的变化。这种方式的优点是不需要服务器端配置支持。
原理:
- 哈希部分的变化不会导致页面的重新加载,浏览器会触发
hashchange
事件。 -
不管是直接在链接标签上指定<a href='#abc'>test</a>还是通过location.hash='#1234'设置hash都会导致浏览器地址栏变化,从而触发hashchange事件
- 在前端路由中,监听
hashchange
事件,可通过event.newURL或location.hash来获取改变后的页面地址。
// 监听hash变化事件 window.addEventListener("hashchange", () => { const hash = window.location.hash.slice(1); // 获取#后面的路由路径 renderPage(hash); }); // 页面渲染函数 function renderPage(route) { if (route === "home") { document.getElementById("app").innerHTML = "<h1>Home Page</h1>"; } else if (route === "about") { document.getElementById("app").innerHTML = "<h1>About Page</h1>"; } else { document.getElementById("app").innerHTML = "<h1>Not Found</h1>"; } }
历史记录路由(History Routing)
历史记录路由使用HTML5的History API
,通过操作浏览器的历史记录来实现路由。这种方式更贴近真实的URL结构,但需要服务器配置,以防止用户直接访问某个URL时服务器找不到对应的资源。
原理:
history.pushState()
、history.replaceState()
:这些方法可以添加或替换历史记录条目,同时改变URL而不触发页面刷新。popstate
事件:用户点击浏览器的前进或后退按钮时会触发该事件,前端应用可以通过监听popstate
事件来根据URL渲染不同的页面。
// 路由跳转函数 function navigateTo(route) { history.pushState(null, null, route); // 修改URL且不会刷新页面 renderPage(route); // 渲染对应的页面内容 } // 页面渲染函数 function renderPage(route) { if (route === "/home") { document.getElementById("app").innerHTML = "<h1>Home Page</h1>"; } else if (route === "/about") { document.getElementById("app").innerHTML = "<h1>About Page</h1>"; } else { document.getElementById("app").innerHTML = "<h1>Not Found</h1>"; } } // 监听popstate事件,用于处理前进/后退 window.addEventListener("popstate", () => { renderPage(window.location.pathname); });
- 通过pushState/replaceState时 不会触发 popstate 事件。因此需要拦截 pushState/replaceState
window.history.pushState = new Proxy(window.history.pushState, { apply(target, thisBinding, args) { //下个页面的地址 const nextPathName = args[2]; // 继续执行原有的程序 return target.apply(thisBinding, args); } });
路由匹配核心原理
以一个最基本的react-router组件进行分析:
<Router history={hashHistory}> <Route path="/" component={App}/> <Route path="/repos" component={Repos}/> <Route path="/about" component={About}/> </Router>
URL 变更 -> history
变化 -> location
变化 -> Router
组件收到新的 location
,遍历Router子组件,取出Route.path的值用path-url-regexp进行匹配,如果匹配,则渲染component属性指定的组件