Yii2中使用JQuery实现树形视图层级显示异常求助
修复Yii2中TreeView子级显示位置错误的问题
我帮你排查了下代码里的问题,主要是动态元素事件绑定失效、DOM定位错误和重复ID冲突这几个点导致了子级分类(比如Cat-1.1.1)没有显示在对应父级(Cat-1.1)下,反而出现父级被移除、子级错位的情况。下面是具体的解决方案:
关键问题分析
- 重复ID冲突:HTML和JS里多次使用
id="video_search",ID是全局唯一的,重复使用会导致选择器无法精准定位目标元素。 - 动态元素事件绑定错误:直接给
.category_child绑定click事件,但这个元素是AJAX请求后动态生成的,常规绑定无法生效。 - DOM插入逻辑混乱:生成子级HTML后没有精准插入到对应父级的
category_nested容器,而是全局插入,导致结构错乱。
修改后的代码实现
1. 修正HTML代码(解决重复ID问题)
把所有id="video_search"改成class="video_search",并确保容器结构清晰:
<html> <body> <div class="content-body"> <div class="row "> <div class="col-lg-12 col-md-12 col-12 "> <ul id="myUL" class="datatable-search-div" style="display: none;"> <?php if (!empty($model)) { foreach ($model as $key => $value) { ?> <li class="category_video"> <span class="caret"> <a href="<?= $value['uuid']; ?>" class="video_search" data-uuid="<?= $value['uuid']; ?>" data-parentid="<?= $value['parent_id']; ?>" data-name="<?= $value['name']; ?>" data-toggle="tab" onclick="videoShow('<?= $value['uuid']; ?>');"> <?= $value['name']; ?> </a> </span> <ul class="nested" data-id="<?= $value['uuid']; ?>" id="tab_<?= $value['uuid']; ?>" role="tablist" style="display:none;"> <li class="category_child" data-id="<?= $value['uuid']; ?>"> <ul class="category_nested" id="nested_<?= $value['uuid']; ?>" role="tablist"></ul> </li> </ul> </li> <?php } } ?> </ul> </div> </div> </div> <div class="tab-content float-left vertical col-xl-12 col-lg-12 col-md-3 col-3 left-aligned" id="myTabContent5" style="display:none;"> <?php if (!empty($model)) { ?> <div id="content_<?= $value['uuid']; ?>" class="tab-pane showVideo fade active show"></div> <?php } ?> </div> </body> </html>
2. 修正注册JS代码(修复事件绑定和DOM插入逻辑)
$this->registerJs( ' function videoShow(id){ var url = "' . Url::to(['test/get-videos-from-category']) . '?id="+id; $.ajax({ type: "GET", url: url, beforeSend: function() { blockBody(); }, success:function(data){ unblockBody(); $("#myTabContent5").show(); $(".showVideo").html(data); // 解析返回的分类数据(从hidden元素中提取) var categoryNodes = []; $(data).find(".hidden").each(function(){ categoryNodes.push({ name: $(this).find(".category_name").text(), uuid: $(this).find(".category_uuid").text(), parentId: $(this).find(".category_parent_id").text() }); }); // 找到当前点击的父级容器(根据传入的id) var parentNestedContainer = $("#nested_" + id); if(parentNestedContainer.length === 0) return; // 生成子级HTML并插入到对应父容器 var childHtml = ""; categoryNodes.forEach(function(node){ childHtml += `<li class="category_child" data-id="${node.uuid}">`; childHtml += `<a href="${node.uuid}" class="video_search" data-uuid="${node.uuid}" data-parentid="${node.parentId}" data-name="${node.name}" data-toggle="tab" onclick="videoShow(\'${node.uuid}\');" style="margin-left: 20px;">${node.name}</a>`; childHtml += `<ul class="category_nested" id="nested_${node.uuid}" role="tablist"></ul>`; childHtml += `</li>`; }); parentNestedContainer.html(childHtml); // 处理展开/收起样式 $(`#tab_${id}`).show(); $(`#tab_${id}`).closest(".category_video").find(".caret").addClass("caret-down"); }, error:function(e){ unblockBody(); showErrorMessage(e.responseText); } }); } // 用事件委托处理动态生成的.caret点击事件(展开/收起) $(document).on("click", ".caret", function(e){ e.preventDefault(); var $this = $(this); var $siblingNested = $this.next(".nested"); // 切换展开/收起状态 $siblingNested.toggle(); $this.toggleClass("caret-down"); // 关闭其他同级展开的节点 $this.closest(".category_video").siblings().find(".nested").hide(); $this.closest(".category_video").siblings().find(".caret").removeClass("caret-down"); }); ', View::POS_END );
关键改动说明
- 唯一ID命名:把容器ID改成
tab_xxx和nested_xxx的格式,确保每个节点的ID唯一,避免选择器冲突。 - 事件委托:用
$(document).on("click", ".caret", ...)处理动态元素的点击事件,确保新生成的节点也能触发展开/收起逻辑。 - 精准DOM插入:根据传入的父级ID找到对应的
category_nested容器,把生成的子级HTML直接插入到该容器中,保证子级属于正确的父节点。 - 简化逻辑:去掉了原JS中冗余的重复赋值和混乱的DOM操作,让代码逻辑更清晰。
内容的提问来源于stack exchange,提问作者Akash Shrimali
相关产品推荐
相关产品推荐

