日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 前端技术 > HTML >内容正文

HTML

简单的基于hash和hashchange的前端路由

發布時間:2025/4/5 HTML 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 简单的基于hash和hashchange的前端路由 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

hash定義

hash這個玩意是地址欄上#及后面部分,代表網頁中的一個位置,#后面部分為位置標識符。頁面打開后,會自動滾動到指定位置處。
位置標識符 ,一是使用錨點,比如<a name="demo"></a>,二是使用id屬性,比如 <span id="demo" ></span>

帶hash的請求

當打開http://www.example.com/#print服務器實際收到的請求地址是http://www.example.com/,是不帶hash值的。
那么你真想帶#字符咋辦,轉義啊, #轉義字符為%23。也許有人會說,我咋知道這個轉義啊,呵呵噠encodeURIComponent。

hashchange事件

從The HashChangeEvent interface可以看到hashchange事件的參數HashChangeEvent繼承了Event,僅僅多了兩個屬性

  • oldURL 先前會話歷史記錄的URL
  • newURL 當前會話歷史記錄的URL
    簡單的調用方式
window.onhashchange = function(e){console.log('old URL:', e.oldURL)console.log('new URL', e.newURL)}

hash | CAN I USE 上可以看到除了IE8一下和那個尷尬的Opera Mini,hashchange事件都是支持得很好。那么怎么做到兼容,用MDN的代碼做個引子

function(window) { if ("onhashchange" in window) { return; }var location = window.location,oldURL = location.href,oldHash = location.hash;setInterval(function() {var newURL = location.href, newHash = location.hash;if (newHash != oldHash && typeof window.onhashchange === "function") { window.onhashchange({type: "hashchange",oldURL: oldURL,newURL: newURL});oldURL = newURL;oldHash = newHash;}}, 100); }

hash history 簡單版本實現

從上面可以得知,我們的實現思路就是監聽hashchange事件,這里先拋開兼容性問題。
1 首先監聽hashchange事件,定義個RouterManager函數

  • bind(this)讓函數this指向RouterManager實例
  • 取到oldURL和newURL,同時查找一下是否注冊,然后加載相關路由
function RouterManager(list, index) {if (!(this instanceof RouterManager)) {return new RouterManager(arguments)}this.list = {} || listthis.index = indexthis.pre = nullthis.current = nullwin.addEventListener('hashchange', function (ev) {var pre = ev.oldURL.split('#')[1],cur = ev.newURL.split('#')[1],preR = this.getByUrlOrName(pre),curR = this.getByUrlOrName(cur)this.loadWithRouter(curR, preR)}.bind(this))}

2 定義添加,刪除,加載,和初始化等方法

  • add的時候,判斷是不是string, 如果是,重新構造一個新的router實例配置
  • load這里主要是用來還原直接輸入帶hash的地址,比如 http://ex.com/#music
  • loadWithRouter是最終渲染的入口
  • getByUrlOrName,你可以通過名字和path查找路由,name是方便日后擴展
  • setIndex設置默認路由地址
  • go, back, forward同history的方法
  • init里面會檢測地址是不是帶hash,然后走不通的邏輯。history.replaceState這是因為,如果不這么做, http://ex.com/跳轉到http://ex.com/#/music會產生兩條歷史記錄,這是我們不期望的。
RouterManager.prototype = {add: function (router, callback) {if (typeof router === 'string') {router = {path: router,name: router,callback: callback}}this.list[router.name || router.path] = router},remove: function (name) {delete this.list[name]},get: function (name) {return this.getByUrlOrName(name)},load: function (name) {if (!name) {name = location.hash.slice(1)}var r = this.getByUrlOrName(name)this.loadWithRouter(r, null)},loadWithRouter(cur, pre) {if (cur && cur.callback) {this.pre = this.current || curcur.callback(cur, pre)this.current = cur} else {this.NOTFOUND('未找到相關路由')}},getByUrlOrName: function (nameOrUrl) {var r = this.list[nameOrUrl]if (!r) {r = Object.values(this.list).find(rt => rt.name === nameOrUrl || rt.path === nameOrUrl)}return r},setIndex: function (nameOrUrl) {this.indexRouter = this.getByUrlOrName(nameOrUrl)},go: function (num) {win.history.go(num)},back: function () {win.history.back()},forward: function () {win.history.forward()},init: function () {// 直接輸入是帶hash的地址,還原if (win.location.hash) {/* 模擬事件var ev = document.createEvent('Event')ev.initEvent('hashchange', true, true)ev.oldURL = ev.newURL = location.hrefwin.dispatchEvent(ev) */this.load()} else if (this.indexRouter) { // 是不帶hash的地址,跳轉到指定的首頁if ('replaceState' in win.history) {// 替換地址win.history.replaceState(null, null, win.location.href + '#' + this.indexRouter.path)} else {win.location.hash = this.indexRouter.path}}}}

3 公布函數

RouterManager.prototype.use = RouterManager.prototype.addwin.Router = RouterManager

4 頁面怎么配置,簡單的利用a標簽href

<ul><li><li><a href="#/m1">菜單1</a></li><ul><li><a href="#/m11">菜單11</a></li><li><a href="#/m12">菜單12</a></li></ul></li><li><a href="#/m2">菜單2</a></li><li><a href="#/m3">菜單3</a></li> </ul>

5 注冊,當然你也可以通過選擇器批量注冊

var router = new Router() router.NOTFOUND = function (msg) {content.innerHTML = msg } router.use('/m1', function (r) {req(r.path.slice(1)) }) router.use('/m11', function (r) {req(r.path.slice(1)) }) router.use('/m12', function (r) {req(r.path.slice(1)) }) router.use('/m2', function (r) {req(r.path.slice(1)) }) router.use('/m3', function (r) {req(r.path.slice(1)) }) router.setIndex('/m1') router.init()

為了方便演示,定義req,ajax方法,模擬ajax請求

function req(url) {ajax(url, function (res) {content.innerHTML = res}) }function ajax(id, callback) {callback({'m1': '菜單1的主區域內容','m11': '菜單11的主區域內容','m12': '菜單12的主區域內容','m2': '菜單2的主區域內容','m3': '菜單3的主區域內容'}[id] || '404 Not Found!') }

6 demo地址

hash-Router1.0


7 源碼地址
簡單的前端hash路由

8 下一步
這就成了最簡單最基本的路由了。讓然還有很多要考慮,比如如下

  • 動態路由匹配
  • 嵌套路由
  • 重定向和別名
  • 錯誤捕捉
  • 生命周期鉤子
  • 等等等
  • hash | CAN I USE
    The HashChangeEvent interface
    onhashchange | MDN
    window.location.hash 使用說明
    JS單頁面應用實現前端路由(hash)
    Ajax保留瀏覽器歷史的兩種解決方案(Hash&Pjax)
    理解瀏覽器的歷史記錄
    理解瀏覽器歷史記錄(2)-hashchange、pushState
    Web開發中 前端路由 實現的幾種方式和適用場景
    自己動手寫一個前端路由插件
    vue-router
    react-router

    總結

    以上是生活随笔為你收集整理的简单的基于hash和hashchange的前端路由的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。