如何阻止jQuery UI Sortable嵌套容器移动并消除报错?
问题描述
我正在配置嵌套DIV结构的jQuery UI Sortable组件,需求是仅允许带有moveFile类的元素可拖拽,其余所有DIV都要禁止移动。目前示例里的MoveDocument可以正常拖拽,但我需要阻止带编号的容器(.fldrIcon元素)被拖拽,同时消除以下报错:
Error: {
"message": "HierarchyRequestError: Node.insertBefore: The new child is an ancestor of the parent",
"filename": "https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js",
"lineno": 2,
"colno": 0
}
复现步骤:点击编号左侧并向下拖拽,拖拽编号2及以上的元素时会触发该报错。
当前代码
JavaScript
$(document).ready(function () { $(".moveFldr").sortable({ connectWith: "div.moveFldr :not(.fldrIcon) :not(span)", placeholder: "placeHolder", cancel: ".fldrIcon, .voidDoc", }); $(".fldrIcon").sortable("disable"); });
CSS
.fldrIcon:before { cursor: pointer; content: counter(folders); } .voidDoc { text-decoration: line-through; text-decoration-color: red; } #voidDoc { background-color:#FFF; border-radius:5px; color:#000; display:none; padding:5px; min-width:400px; min-height: 130px; } .voidedDoc, .newDoc, .oldDoc { text-decoration: none !important; } .placeHolder { border-style: dashed; border-color: #000; height: 15px; } .grnDot, .redDot, .ylwDot { height: 10px; width: 20px; border-color: #000; border-style: solid; border-width: 1px; border-radius: 50%; font-size: 10px; display:inline-block; text-align: center; padding-bottom: 10px; } .subFixField { font-weight: 700; } .fixField { text-align:center; } .grnDot { background-color: #5efc03; color: #000; } .redDot { background-color: #FF0000; color: #FFF; } .ylwDot { background-color: #ffff00; color: #000; } .fldrIcon { counter-increment: folders; }
HTML
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script> <link href="https://code.jquery.com/ui/1.13.2/themes/base/jquery-ui.css" rel="stylesheet"/> <script src="https://code.jquery.com/ui/1.13.2/jquery-ui.js"></script> <div style="text-align:center;"> <div class="inlineBlock moveFldr" style="text-align:left;"> <div id="C1" class="moveFldr lnkItems" data-cid="1" style="padding-left:30px;"> <div id="F1" class="fldrIcon contextMenu moveFldr">. Procedures for Suppliers</div> <div id="C2" class="moveFldr lnkItems " data-cid="2" style="padding-left:30px;"> <div id="F2" class="fldrIcon contextMenu moveFldr">. Performance of Activates</div> <div id="L101" class="upDoc moveFile fileIcon2 hideFile" style="margin-left: 15px;">MoveDocument</div> <div id="C3" class="moveFldr lnkItems " data-cid="3" style="padding-left:30px;"> <div id="F3" class="fldrIcon contextMenu moveFldr">. Verification Documents</div> <div id="C4" class="moveFldr lnkItems " data-cid="4" style="padding-left:30px;"> <div id="F4" class="fldrIcon contextMenu moveFldr">. Performance Evaluation</div> </div> <div id="C5" class="moveFldr lnkItems " data-cid="5" style="padding-left:30px;"> <div id="F5" class="fldrIcon contextMenu moveFldr">. Verification Reports</div> </div> <div id="C6" class="moveFldr lnkItems " data-cid="6" style="padding-left:30px;"> <div id="F6" class="fldrIcon contextMenu moveFldr">. Testing Water</div> <div id="C19" class="moveFldr lnkItems " data-cid="19" style="padding-left:30px;"> <div id="F19" class="fldrIcon contextMenu moveFldr">. 2022-2023</div> </div> <div id="C20" class="moveFldr lnkItems " data-cid="20" style="padding-left:30px;"> <div id="F20" class="fldrIcon contextMenu moveFldr">. 2023-2024</div> </div> <div id="C21" class="moveFldr lnkItems "> <div id="F21" class="fldrIcon contextMenu moveFldr" style="padding-left:30px;">. 2024-2025</div> </div> <div id="C22" class="moveFldr lnkItems " data-cid="22" style="padding-left:30px;"> <div id="F22" class="fldrIcon contextMenu moveFldr">. 2025-2026</div> </div> </div> <div id="C7" class="moveFldr lnkItems " data-cid="7" style="padding-left:30px;"> <div id="F7" class="fldrIcon contextMenu moveFldr" data-cid="7">. Supplier’s Certification</div> </div> <div id="C8" class="moveFldr lnkItems " data-cid="8" style="padding-left:30px;"> <div id="F8" class="fldrIcon contextMenu moveFldr">. Training Program</div> </div> <div id="C10" class="moveFldr lnkItems " data-cid="10" style="padding-left:30px;"> <div id="F10" class="fldrIcon contextMenu moveFldr">. Drug Testing</div> </div> <div id="C11" class="moveFldr lnkItems " data-cid="11" style="padding-left:30px;"> <div id="F11" class="fldrIcon contextMenu moveFldr">. Annual 3rd Party Audit</div> <div id="C12" class="moveFldr lnkItems " data-cid="12" style="padding-left:30px;"> <div id="F12" class="fldrIcon contextMenu moveFldr" data-cid="12">. Corrective Action Reports</div> </div> </div> <div id="C17" class="moveFldr lnkItems " data-cid="17" style="padding-left:30px;"> <div id="F17" class="fldrIcon contextMenu moveFldr">. Other Documents</div> </div> <div id="C9" class="moveFldr lnkItems " data-cid="9" style="padding-left:30px;"> <div id="F9" class="fldrIcon contextMenu moveFldr">. Analysis Review</div> </div> </div> </div> </div> </div> </div>
解决方案
问题根源是给所有.moveFldr元素都绑定了Sortable,包括嵌套容器和带编号的.fldrIcon,导致拖拽时DOM层级操作冲突,触发HierarchyRequestError;同时cancel配置没彻底阻止容器拖拽,反而因为嵌套Sortable实例互相干扰加剧了问题。
按以下方式修改代码:
$(document).ready(function () { // 给所有.moveFldr容器绑定Sortable,但仅允许.moveFile元素拖拽 $(".moveFldr").sortable({ items: ".moveFile", // 核心:只指定moveFile类元素为可拖拽项 connectWith: ".moveFldr", // 简化跨容器拖拽规则,按需保留 placeholder: "placeHolder", cancel: ".fldrIcon, .voidDoc, .lnkItems" // 明确禁止容器类元素触发拖拽 }); });
如果只需要特定层级的容器支持文件拖拽,可以更精准地选择目标容器:
// 仅给直接包含.moveFile的.moveFldr容器绑定Sortable $(".moveFldr:has(.moveFile)").sortable({ items: ".moveFile", placeholder: "placeHolder", cancel: ":not(.moveFile)" // 除了moveFile,其他元素都禁止拖拽 });
逻辑说明
items: ".moveFile"从根源上限定了可拖拽元素,直接阻止容器(包括带编号的.fldrIcon)被拖拽。- 避免给嵌套DOM元素重复绑定Sortable,消除父/子容器同时触发Sortable逻辑导致的DOM插入层级冲突。
- 移除不必要的
sortable("disable")调用,通过配置即可实现需求。
内容的提问来源于stack exchange,提问作者James
相关产品推荐
相关产品推荐

