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");
搞定是搞定了,但是上面的代码都是直接写的,没测试,所以自己小心着用。
添加回答
举报