1 回答

TA貢獻1790條經驗 獲得超9個贊
這個問題很有意思,總結一下,你要解決的問題有兩個
根據當前 URL 找到匹配的
href
屬性找到對應第 1 找到的
href
屬性的那個<a>
,對它以及它的幾級父元素添加狀態
下面來一個一個的解決
示例都是用的 es6 語法,不懂的話可以自己去 babel-try it out,或者 typescript playgournd 轉換成 es5 的。
找到匹配的 href
首先,得讓 href
和當前地址處于同樣的目錄級別表示。比如 href 里是 admin/....
,那當前頁面地址 window.location.pathname
也要處理成這樣,比如當前地址可能是 /admin/...
,要去掉第一個 /
;或者當前地址是 /appname/admin/....
,要去掉前面的 /appname/
。的過來,處理每個 href
去適配當前地址的表示也是一樣的(其實這樣更合理,只是處理起來更麻煩)
const root = "/appname/";const menuUrls = $(".sidebar-menu a").map(function() { return `${root}${$(this).attr("href")}`; });
這會得到包含所有鏈接的 href
屬性的一個數組(jQuery 對象),我們可以遍歷這個數組來尋找匹配的 URL,不過找到 URL 之后再去找對應的 <a>
是件麻煩事,所以,其實應該生成一個 map(JS 對象)
const urlsMap = $(".sidebar-menu a") .toArray() .reduce((map, a) => { const $a = $(a); const url = `${root}${$a.attr("href")}`; map[url] = $a; return map; }, {});
現在會得到一個 urlsMap
,它是鍵是 URL,就是根據 href
處理而來的 URL。值是一個被 jQuery 封裝的 <a>
的 DOM 對象,一一對應的關系。
第一輪,精確匹配
let pathname = window.location.pathname;let foundUrl = Object.keys(urlsMap) .fitler(url => { return url === pathname; })[0];
如果 foundUrl
是一個字符串,說明找到了,不然就是沒找到(因為 filter 的結果是個空數組,所以它的第 0 個元素是 undefined)。如果沒找到,再進行第二輪,這時候需要截掉 pathname
的最后一部分,這也是 pathname
和 foundUrl
用 let
申明而不用 const
申明的原因
第二輪,startsWith 匹配
if (!foundUrl) { // 去掉最后一個 / 及其后的部分 pathname = pathname.replace(/\/[^\/]+$/, ""); foundUrl = Object.keys(urlsMap) .filter(url => { return url.startsWith(pathnem); })[0]; }
如果這樣還沒找到,你還需要再往前找,你可以考慮用一個循環代替上面的 if
分支,注意循環的結束條件,不要搞成死循環了。最終也沒找到,那就拉倒吧。
如果找到了,那么 foundUrl
對應的那個 <a>
就是要高亮的。這個 <a>
很好找,因為我們建了映射表
const $a = urlsMap[foundUrl];
下面進行第二步
改變相關元素的狀態
這時候就需要找三個東西,<a>
外層的 <li>
,再外層的 .treeview-menu
和再外層的 .treeview
。如果都是直接父級關系,那很好找,依次取 .parent()
就好。如果不是,那就用 .closest()
,下面的代碼假設是這種情況
$li = $a.closest("li"); $treeViewMenu = $li.closest(".treeview-menu"); $treeView = $treeViewMenu.closest(".treeview");
都找到了,改個類就容易了(因為 jQuery 的容錯性,完全不需要去判斷找沒找到,直接改就是了)
$li.addClass("active"); $treeViewMenu.addClass("menu_open"); $treeView.addClass("active");
搞定是搞定了,但是上面的代碼都是直接寫的,沒測試,所以自己小心著用。
添加回答
舉報