多组处理, 仅展开一个区块的折叠效果(原生Js和jQ版)
上午在项目中遇到的一个问题, 折腾了半小时才把思路理顺. 需求是, 同一个页面, 有多组(不固定), 每组区块数量不一定一样的小区块. 要求每次只展开一个区块. 实现原理其实很简单, 点击导航, 若它的区块为隐藏, 则展开它, 同时, 隐藏掉同组其他区块; 若它的区块为展开, 则隐藏它, 同时, 展开同组其他区块中的一个. 一开始以为仅仅简单的两个遍历就能搞定. 但事实并非如此. 冷静思考了下, 通过点击的元素取到当前组的相关元素, 再单独处理当前组才合理. 顺着这个思路, 功能终于实现了, 写了原生Js版本, 用同样的思路写了个jQ版本. 时间关系, 写的也比较零散, 就没有封装. 其实, 对这种思路也不是很满意, 感觉太散了, 哪位大师有更好的思路请赐教.
另, 在演示页面中, 点击jQ版区块的标题, 会有一个Js错误, 那是因为获取Js版下的h2时, 我偷了个懒, 把jQ的也遍历进去了. 我想, 实际应用中, 也不会有人同一个效果, 一边用Js一边用jQ吧.
核心代码点此查看样例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 | //原生Js版本 ***** start window.onload= function (){ //共用函数区 var iBase={ //document.getElementById Id: function (name){ return document.getElementById(name)}, //通过class获取元素 GetByClass: function (name,tagName,elem){ var c=[]; var re= new RegExp( '(^|\\s)' +name+ '(|\\s$)' ); var e=(elem || document).getElementsByTagName(tagName || '*' ); for ( var i=0; i < e.length; i++){ if (re.test(e[i].className)){ c.push(e[i]); } } return c; }, //获取样式属性 AttrStyle: function (elem,attr){ if (elem.attr){ return elem.style[attr]; } else if (elem.currentStyle){ return elem.currentStyle[attr]; } else if (document.defaultView && document.defaultView.getComputedStyle){ attr=attr.replace(/([A-Z])/g, '-$1' ).toLowerCase(); return document.defaultView.getComputedStyle(elem, null ).getPropertyValue(attr); } else { return null ; } }, //获取祖辈元素中符合指定样式的元素 Parents: function (elem,name){ var r= new RegExp( '(^|\\s)' +name+ '(|\\s$)' ); elem=elem.parentNode; if (elem!= null ){ return r.test(elem.className) ? elem : iBase.Parent(elem,name) || null ; } }, //取索引值 Index: function (cur,obj){ for ( var i=0; i < obj.length; i++){ if (obj[i]==cur){ return i; } } } } //变量定义 var listBox=iBase.GetByClass( 'js' , 'div' ); var navItem=iBase.Id( 'demo' ).getElementsByTagName( 'h2' ); //此处将jQ区块中的h2也取到了,所以页面会有个小小的错误 var icoItem= null ,boxItem= null ,boxDisplay= null ,elemIndex= null ,elemParent= null ; //初始化展开第一个 for ( var i=0; i < listBox.length;i++){ iBase.GetByClass( 'box' , 'div' ,listBox[i])[0].style.display= 'block' ; listBox[i].getElementsByTagName( 'span' )[0].innerHTML= '-' ; } //遍历所有点击项 for ( var i=0; i < navItem.length;i++){ navItem[i].onclick= function (){ elemParent=iBase.Parents( this , 'js' ); //获取当前点击所在区块 navItem=elemParent.getElementsByTagName( 'h2' ); //获取当前区块下的点击项 icoItem=elemParent.getElementsByTagName( 'span' ); //获取当前区块下的展开关闭 boxItem=iBase.GetByClass( 'box' , 'div' ,elemParent); //获取需要控制的区块 elemIndex=iBase.Index( this ,navItem); //获取当前点击在当前区块点击项中的索引 //切换展开关闭图标 icoItem[elemIndex].innerHTML= icoItem[elemIndex].innerHTML== '-' ? '+' : '-' ; if (iBase.AttrStyle(boxItem[elemIndex], 'display' )== 'block' ){ //控制项展开状态下,隐藏当前,展开其他的第一项 //此处有个展开0/1的判断,因为当点击第一个时是不能再展开第一个的 boxItem[elemIndex].style.display= 'none' ; if (elemIndex==0){ boxItem[1].style.display= 'block' ; icoItem[1].innerHTML= '-' } else { boxItem[0].style.display= 'block' icoItem[0].innerHTML= '-' } } else { //控制项展开状态下,展开当前,隐藏其他项 boxItem[elemIndex].style.display= 'block' ; for ( var k=0;k < boxItem.length; k++){ if (k!=elemIndex){ boxItem[k].style.display= 'none' ; icoItem[k].innerHTML= '+' ; } } } } } } //jQuery版本 ***** start $( function (){ //变量定义区 var _listBox=$( '.jq' ); var _navItem=$( '.jq>h2' ); var _boxItem= null , _icoItem= null , _parents= null , _index= null ; //初始化第一个展开 _listBox.each( function (i){ $( this ).find( 'div.box' ).eq(0).show(); $( this ).find( 'h2>span' ).eq(0).text( '-' ); }); //遍历所有的点击项 _navItem.each( function (i){ $( this ).click( function (){ //找到当前点击父元素为listbox(单个区块)的元素 _parents=$( this ).parents( '.listbox' ); _navItem=_parents.find( 'h2' ); //此区块中的点击项 _icoItem=_parents.find( 'span' ); //此区块中的展开关闭图标 _boxItem=_parents.find( 'div.box' ); //此区块中展开关闭项 _index=_navItem.index( this ); //取得当前点击在当前区块下点击项中的索引值 if (_boxItem.eq(_index).is( ':visible' )){ //若当前点击项下的展开关闭项是显示的,则关闭,同时展开另外项中的第一个 _boxItem.eq(_index).hide().end().not( ':eq(' +_index+ ')' ).first().show(); _icoItem.eq(_index).text( '+' ).end().not( ':eq(' +_index+ ')' ).first().text( '-' ); } else { //若当前点击项下的展开关闭项是隐藏的,则展开,同时隐藏其他项 _boxItem.eq(_index).show().end().not( ':eq(' +_index+ ')' ).hide(); _icoItem.eq(_index).text( '-' ).end().not( ':eq(' +_index+ ')' ).text( '+' ); } }); }); }); |
1 | 原文发布于Mr.Think的博客: http: //mrthink.net/jsjq-flod-onlyone/ 转载请注明 |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?