如何优化jQuery代码实现特定位置仅插入一次li元素?
这个问题我太熟了!本质上是两个核心问题:一是递归生成列表时重复调用test()导致多次插入,二是外部调用时目标DOM元素还没生成所以没效果。下面给你几个靠谱的解决方案,按需选择:
方案1:在列表完全渲染后调用插入函数(最直接)
问题根源之一是你在递归函数getNestedLists里调用test(),而递归会执行N次(对应列表的层级/元素数量),自然会插N个Hello元素。另外外部调用无效是因为此时列表还没生成,$('#navbar-collapse-menu li:eq(0)')找不到任何元素。
解决办法很简单:找到你调用getNestedLists并把生成的列表添加到DOM的地方,等列表完全插入到页面后再调用一次test()。
比如假设你原来的调用逻辑是这样的:
// 生成菜单 var menu = getNestedLists(yourSource, 0); // 把菜单添加到页面 $('#navbar-collapse-menu').append(menu); // 这里!等菜单渲染完成后,只调用一次test() test();
同时记得把getNestedLists里的test()调用删掉——现在只需要在最后执行一次就够了。
方案2:给插入函数加防重复判断(无需改动调用时机)
如果你没办法调整test()的调用时机,那可以给要插入的元素加一个唯一标识,每次执行test()前先检查这个元素是否已经存在,不存在才插入:
修改后的test()函数:
function test() { // 用唯一class判断是否已插入 if (!$('#navbar-collapse-menu li.hello-menu-item').length) { $('#navbar-collapse-menu li:eq(0)').after('<li class="hello-menu-item" style="background:orange">Hello</li>'); } }
这样不管test()被调用多少次,第一次插入后后续调用都会跳过,最终只会有一个Hello元素。
方案3:整合插入逻辑到列表生成流程(最优雅)
把插入Hello元素的逻辑直接整合到列表生成的最后一步,避免在递归里调用无关函数,代码结构更清晰:
比如新增一个构建菜单的函数,在生成完所有列表元素后,一次性插入Hello:
function buildNavbarMenu(source) { var nestedList = getNestedLists(source, 0); if (nestedList && nestedList.children('li').length > 0) { // 直接在生成的列表里插入Hello元素,只执行一次 nestedList.children('li:eq(0)').after('<li style="background:orange">Hello</li>'); // 把最终菜单添加到DOM $('#navbar-collapse-menu').append(nestedList); } }
然后调用buildNavbarMenu(yourSource)代替原来的getNestedLists调用,同时删掉getNestedLists里的test()调用即可。
为什么原来的代码会出问题?
- 递归调用
getNestedLists时,每次进入函数都会执行test(),递归多少次就插多少次Hello; - 外部调用
test()时,getNestedLists还没执行完,列表元素还没被添加到DOM,$('#navbar-collapse-menu li:eq(0)')找不到目标元素,所以after()没有任何效果。
内容的提问来源于stack exchange,提问作者Sarah

