如何通过KnockoutJS获取HTML中accordion类并实现手风琴展开交互效果
问题根因
- API混用错误:
jQuery.getElementsByClassName是无效写法,getElementsByClassName是原生DOM文档对象的方法,jQuery选择类名元素的语法为$('.accordion') - 生命周期调用错误:Durandal框架的
activate钩子触发时,关联的视图DOM还未被渲染插入到页面中,此时无论用什么选择器都无法获取到.accordion元素 - 实现思路不符合KnockoutJS的MVVM设计规范:手动操作DOM绑定事件的方式,在动态渲染(比如
foreach生成)的手风琴项场景下会完全失效
方案1:快速修复现有代码
将原有逻辑从activate钩子迁移到Durandal的attached钩子(DOM完成插入后触发),同时修正选择器写法:
define(['viewmodels/shell', 'durandal/services/logger', 'mediator-js', 'knockout', 'toastr', 'jquery'], function (shell, logger, mediator, ko, toastr, $) { var vm = { shell: shell, activate: activate, attached: attached, // 新增attached生命周期声明 mediator: mediator } function activate() { return true; } // 原有逻辑移到此处 function attached() { var acc = document.getElementsByClassName("accordion"); var panel = document.getElementsByClassName('panel'); for (var i = 0; i < acc.length; i++) { acc[i].onclick = function () { var setClasses = !this.classList.contains('active'); setClass(acc, 'active', 'remove'); setClass(panel, 'show', 'remove'); if (setClasses) { this.classList.toggle("active"); this.nextElementSibling.classList.toggle("show"); } } } function setClass(els, className, fnName) { for (var i = 0; i < els.length; i++) { els[i].classList[fnName](className); } } } return vm; });
方案2:符合KnockoutJS规范的标准实现
无需手动操作DOM,通过数据驱动视图状态,适配动态生成的手风琴项场景:
- 视图模型新增状态管理:
var vm = { shell: shell, activate: activate, mediator: mediator, // 手风琴列表数据,根据你的业务场景替换实际内容 accordionItems: ko.observableArray([ {title: '标题1', content: '内容1'}, {title: '标题2', content: '内容2'}, {title: '标题3', content: '内容3'} ]), // 存储当前激活的手风琴索引,-1表示无激活项 activeAccordionIndex: ko.observable(-1), // 点击切换逻辑 toggleAccordion: function(index) { if(vm.activeAccordionIndex() === index) { vm.activeAccordionIndex(-1); } else { vm.activeAccordionIndex(index); } } }
- 视图模板绑定逻辑:
<!-- ko foreach: accordionItems --> <button class="accordion" data-bind="text: title, css: {'active': $index() === $parent.activeAccordionIndex()}, click: () => $parent.toggleAccordion($index())"> </button> <div class="panel" data-bind="css: {'show': $index() === $parent.activeAccordionIndex()}"> <p data-bind="text: content"></p> </div> <!-- /ko -->
内容的提问来源于stack exchange,提问作者lonelydev101
相关产品推荐
相关产品推荐

