[toc]css
在chrome(版本 70.0.3538.110)測試正常
編寫涉及:css, html,js, node(koa)
在線演示codepenhtml
<div class="hash"> <div class="title">hash 路由</div> <a href="#/one">hash 1</a> <a href="#/two">hash 2</a> <a href="#/three">hash 3</a> <a onclick="hashRoute.skip('other')">other</a> <div id="hashContent"></div> </div> <div class="history"> <div class="title">history 路由</div> <div> <button onclick="historyRoute.skip('pushStateOne')">history.pushState(1)</button> <button onclick="historyRoute.skip('pushStateTwo')">history.pushState(2)</button> <button onclick="historyRoute.skip('pushStateThree')">history.pushState(3)</button> <button onclick="historyRoute.skip('pushStateTwo')">history.replaceState(pushStateTwo)</button> <button onclick="historyRoute.skip('go')">history.go(2)</button> <button onclick="historyRoute.skip('forward')">history.forward()</button> <button onclick="historyRoute.skip('back')">history.back()</button> </div> <div id="historyContent"></div> </div>
.hash a { display: inline-block; padding: 5px 8px; margin: 10px 10px 10px 0; font-size: 15px; text-decoration: none; border: 0; cursor: pointer; color: #fff; background-color: rgb(17, 130, 236); } .title{ margin: 10px 0; padding: 5px 8px; border-left: rgb(168, 168, 168) solid 2px; background-color: rgb(230, 230, 230); } .hash div:last-child{ padding: 6px; min-height: 100px; background-color: rgb(243, 243, 243); } .history{ margin: 10px 0; } .history button { padding: 8px 10px; border: 0; color: #fff; background-color: rgb(250, 144, 44); } .history div:last-child{ margin-top: 10px; padding: 6px; min-height: 100px; background-color: rgb(243, 243, 243); }
class HashRoute { setRoute() { const commandObj = { one: 'page one', two: 'page two', three: 'page three' } const hashRoute = location.hash ? location.hash.slice(2) : 'one' let re = commandObj[hashRoute] document.getElementById('hashContent').innerHTML = re ? re : 'page not find' } skip(path) { window.location.hash= `#/${path}` } init() { window.addEventListener('DOMContentLoaded', this.setRoute) // 1.直接更改瀏覽器地址,在最後面增長或改變#hash; // 2.經過改變location.href 或 location.hash的值; // 3.經過觸發點擊帶錨點的連接; // 4.瀏覽器前進後退可能致使hash的變化,前提是兩個網頁地址中的hash值不一樣 window.addEventListener('hashchange', this.setRoute) } } const hashRoute = new HashRoute() hashRoute.init()
// 服務端有效 class HistoryRoute { constructor() { this.currentPath = '' } renderView(component) { const route = { pushStateOne: 'route pushState one', pushStateTwo: 'route pushState two', pushStateThree: 'route pushState three', replaceState: 'route replaceState', go: 'route go', forward: 'route forward', back: 'route back', notFind: 'not find', } document.getElementById('historyContent').innerHTML = route[component] } // 這裏全部涉及的跳轉都用js方式,不採用a標籤(採用a標籤請設置攔截) skip(path) { const commandObj = { pushStateOne: () => { history.pushState({ path }, path,path) this.renderView(path) }, pushStateTwo: () => { history.pushState({ path }, path, path) this.renderView(path) }, pushStateThree: () => { history.pushState({ path }, path, path) this.renderView(path) }, replaceState: () => { // 是用來修改當前的history實體而不是建立一個新的,好比連轉順序爲1,2,3,1執行replaceState(2),再執行back(),返回1,而不是3 history.replaceState({ path }, path, path) this.renderView(path) }, go: () => { history.go(2) this.renderView('go') }, forward: () => { history.forward() this.renderView('forward') }, back: () => { history.back() }, } this.currentPath = path; commandObj[path]() } init() { window.addEventListener('DOMContentLoaded', () => { // 針對F5刷新問題: // 1.能夠使用?後面跟參數形式 // 2.統一入口利用忽略地址方式(後端配置 /page/:path 忽略page後跟的全部地址,經過前端去請求page後的對應路由數據,以下) const path = location.href.split('/page/') this.skip(path[1]) }) // 調用history.pushState()或history.replaceState()不會觸發popstate。 // 只有在用戶點擊前進回退按鈕,(或history.back(),forward,go) window.addEventListener('popstate', (event) => { console.log('popstate', this.currentPath, event.state); const { state } = event if (state && state.path) { this.renderView(state.path) } else { this.renderView('404') } }) } } const historyRoute = new HistoryRoute() historyRoute.init();
// 結合前端,能夠用如下方式處理 router.get('/page/:path', (ctx, next) => { ctx.response.type = 'html'; // 此處的singlePageRoute.html爲單頁面html容器,即放置本文中的全部代碼文件 ctx.response.body = fs.createReadStream('./dist/public/files/singlePageRoute.html'); return next(); })
歡迎交流 Github