如何让Treeview完全支持RTL并将外层UL设为Bootstrap Timeline
解决方案
问题根源
- 同时引入不同版本Bootstrap(v4和v5 RTL),样式冲突导致RTL失效
- 自定义Treeview样式硬编码
left/margin-left等LTR属性,未适配RTL - 外层
ul未添加timeline类
修改步骤
1. 修复HTML结构与依赖引入
- 移除Bootstrap 4的CSS链接,仅保留Bootstrap 5 RTL版本
- 给外层
ul(#tree2)添加timeline类 - 给页面容器添加
dir="rtl"确保全局文本方向
2. 适配RTL的CSS调整
将所有LTR方向的属性替换为RTL对应属性:
margin-left→margin-rightborder-left→border-rightleft→right- 调整图标、时间线标记的位置
3. 合并优化JS代码
移除重复的treed方法实现,保留带状态标记的版本,避免功能冲突
完整代码
HTML
<div class="row" dir="rtl"> <div class="col-md-4"> <ul id="tree2" class="timeline"> <li class="timeline-item"> <a href="#">TECH</a> <ul> <li>Company Maintenance</li> <li class="timeline-item"> Employees <ul> <li class="timeline-item"> Reports <ul> <li class="timeline-item">Report1 <button type="button" class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#exampleModal" data-bs-whatever="@fat"> <i class="fa fa-plus"></i> </button> <div class="modal fade" id="exampleModal" tabindex="-1" aria-labelledby="exampleModalLabel" aria-hidden="true"> <div class="modal-dialog"> <div class="modal-content"> <div class="modal-header"> <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> </div> <div class="modal-body"> <form> <div class="mb-3"> <label for="recipient-name" class="col-form-label">نص العنصر</label> <input type="text" class="form-control"> </div> </form> </div> <div class="modal-footer"> <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">إغلاق</button> <button type="button" class="btn btn-primary">إرسال</button> </div> </div> </div> </div> </li> <li class="timeline-item">Report2 <button type="button" class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#exampleModal" data-bs-whatever="@fat"> <i class="fa fa-plus"></i> </button> </li> <li class="timeline-item">Report3 <button type="button" class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#exampleModal" data-bs-whatever="@fat"> <i class="fa fa-plus"></i> </button> </li> </ul> </li> <li class="timeline-item">Employee Maint.</li> </ul> </li> <li class="timeline-item">Human Resources</li> </ul> </li> <li class="timeline-item"> XRP <ul> <li>Company Maintenance</li> <li class="timeline-item"> Employees <ul> <li class="timeline-item"> Reports <ul> <li class="timeline-item">Report1 <button type="button" class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#exampleModal" data-bs-whatever="@fat"> <i class="fa fa-plus"></i> </button> </li> <li class="timeline-item">Report2 <button type="button" class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#exampleModal" data-bs-whatever="@fat"> <i class="fa fa-plus"></i> </button> </li> <li class="timeline-item">Report3 <button type="button" class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#exampleModal" data-bs-whatever="@fat"> <i class="fa fa-plus"></i> </button> </li> </ul> </li> <li class="timeline-item">Employee Maint.</li> </ul> </li> <li class="timeline-item">Human Resources</li> </ul> </li> </ul> </div> </div> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.1/dist/css/bootstrap.rtl.min.css"> <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.7.0/css/all.css" integrity="sha384-lZN37f5QGtY3VHgisS14W3ExzMWZxybE1SJSEsQp9S+oqd12jhcu+A56Ebc1zFSJ" crossorigin="anonymous"> <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.1/dist/js/bootstrap.bundle.min.js" integrity="sha384-HwwvtgBNo3bZJJLYd8oVXjrBZt8cqVSpeBNS5n7C8IVInixGAoxmnlMuBnhbgrkm" crossorigin="anonymous"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.1/jquery.js"></script>
CSS
.tree, .tree ul { margin:0; padding:0; list-style:none; margin-right:10px; } .tree ul { margin-right:1em; position:relative } .tree ul ul { margin-right:.5em } .tree ul:before { content:""; display:block; width:0; position:absolute; top:0; bottom:0; right:0; border-right:1px solid } .tree li { margin:0; padding:0 1em; line-height:2em; color:#369; font-weight:700; position:relative; } .tree ul li:before { content:""; display:block; width:10px; height:0; border-top:1px solid; margin-top:-1px; position:absolute; top:1em; right:0 } .tree ul li:last-child:before { background:#fff; height:auto; top:1em; bottom:0 } .indicator { margin-left:5px; } .tree li a { text-decoration: none; color:#369; } .tree li button, .tree li button:active, .tree li button:focus { text-decoration: none; color:#369; border:none; background:transparent; margin:0; padding:0; outline: 0; } .loading { font-style: italic; } .timeline { border-right: 1px solid hsl(0, 0%, 90%); position: relative; list-style: none; } .timeline .timeline-item { position: relative; } .timeline .timeline-item:after { position: absolute; display: block; top: 0; } .timeline .timeline-item:after { background-color: hsl(0, 0%, 90%); right: -38px; border-radius: 50%; height: 11px; width: 11px; content: ""; }
JS
$.fn.extend({ treed: function (o) { var openedClass = 'fa-minus-circle'; var closedClass = 'fa-plus-circle'; if (typeof o != 'undefined'){ if (typeof o.openedClass != 'undefined'){ openedClass = o.openedClass; } if (typeof o.closedClass != 'undefined'){ closedClass = o.closedClass; } }; //initialize each of the top levels var tree = $(this); tree.addClass("tree"); tree.find('li').has("ul").each(function () { var branch = $(this); //li with children ul branch.prepend("<i class='indicator fas " + closedClass + "'></i>"); branch.addClass('branch'); // declare a flag to toggle let flag = false; branch.on('click', function (e) { if (this == e.target) { // toggle on click flag = !flag; var icon = $(this).children('i:first'); icon.toggleClass(openedClass + " " + closedClass); // show loader only when its opened, and collpase once toggled if(flag) { $(this).append("<div class='loading'><span class='fa fa-spinner fa-spin'></span></div>"); setTimeout(()=>{ $(this).find('.loading').remove(); $(this).children().children().slideToggle(400); }, 400) } else { $(this).children().children().slideToggle(400); } } }) branch.children().children().toggle(); }); //fire event from the dynamically added icon tree.find('.branch .indicator').each(function(){ $(this).on('click', function () { $(this).closest('li').click(); }); }); //fire event to open branch if the li contains an anchor instead of text tree.find('.branch>a').each(function () { $(this).on('click', function (e) { $(this).closest('li').click(); e.preventDefault(); }); }); //fire event to open branch if the li contains a button instead of text tree.find('.branch>button').each(function () { $(this).on('click', function (e) { $(this).closest('li').click(); e.preventDefault(); }); }); } }); //Initialization of treeviews $('#tree2').treed({openedClass:'fa-folder-open', closedClass:'fa-folder'});
内容的提问来源于stack exchange,提问作者Andandydongola
相关产品推荐
相关产品推荐

