我目前正在与我试图放在一起的界面进行一场激烈的战斗。我在 CSS 和 XHTML 方面相当不错,但我的 jQuery/JavaScript 技能并不令人印象深刻。我正在寻找的与其说是一个严格的答案,不如说是一些关于如何完成这些任务的提示。
我想要实现的是在主要内容区域中包含一些框的布局,当用户按下侧边栏中的链接或框本身的标题时,这些框可以展开和折叠。
dashboard http://www.timkjaerlange.com/foobar/example-dashboard-v01.gif
此外,我希望浏览器通过设置 cookie 记住最后展开的框。如果这还不够,我还希望能够为每个框添加一个“受限”类,从而禁用它,它是相应的侧边栏列表项。
我还希望盒子有一个基于其状态(展开、折叠、受限)的类。
这是我的标记:
<!-- S I D E B A R - L E F T -->
<div id="sidebar-left">
<ul class="sidebar-menu-1">
<li><strong>List headline</strong>
</li>
<li><a href="#">Open module 1</a>
</li>
<li><a href="#">Open module 2</a>
</li>
<li><a href="#">Open module 3</a>
</li>
</ul>
</div><!--/sidebar-left-->
<!-- M A I N - C O N T E N T -->
<div id="main-content">
<!-- dashboard-module -->
<div class="dashboard-module">
<div class="dashboard-module-content limited">
<h2>Headline 1</h2>
<p class="teaser">Teaser-text 1</p>
<div class="expand-collapse">
[some content]
´ </div>
</div>
</div><!--/dashboard-module-->
<!-- dashboard-module -->
<div class="dashboard-module">
<div class="dashboard-module-content limited">
<h2>Headline 2</h2>
<p class="teaser">Teaser-text 2</p>
<div class="expand-collapse">
[some content]
´ </div>
</div>
</div><!--/dashboard-module-->
<!-- dashboard-module -->
<div class="dashboard-module">
<div class="dashboard-module-content limited">
<h2>Headline 3</h2>
<p class="teaser">Teaser-text 3</p>
<div class="expand-collapse">
[some content]
´ </div>
</div>
</div><!--/dashboard-module-->
</div><!--/main-content-->
这是我的 jQuery:
// If the dashboard-module is "limited" do this:
$('div[class*=limited]').each( function(index) {
var countFix = $('div.dashboard-module-content').index(this);
var countFixPlusTwo = countFix + 2;
$( 'ul.sidebar-menu-1 li:nth-child(' + countFixPlusTwo + ')' ).unbind('click').removeClass('selected').addClass('sidebar-menu-locked');
$(this).parent('.dashboard-module').find('h2').unbind('click');
$(this).find('.expand-collapse').remove();
$(this).find('.dashboard-module p:hidden').show();
$(this).addClass('limited-btn');
});
// Check for cookies and do stuff accordingly:
var cookieTest = $.cookie("cookie");
if(cookieTest == null){
$('.js-hidden').hide();
$('ul.sidebar-menu-1 li:not(.sidebar-menu-locked):eq(1)').addClass('selected');
$('.dashboard-module-content:not(.limited):eq(0)' ).toggleClass('hide-btn');
$('.dashboard-module-content:not(.limited):not(:eq(0))' ).removeClass('hide-btn');
$('.expand-collapse:eq(0)' ).show();
};
if(cookieTest != null){
var cookieTestPlusTwo = parseInt(cookieTest, 10) + 2;
$('.dashboard-module-content:eq(' + cookieTest + ')' ).toggleClass('hide-btn');
$('.dashboard-module-content:not(:eq(' + cookieTest + '))' ).removeClass('hide-btn');
$('ul.sidebar-menu-1 li:nth-child(' + cookieTestPlusTwo + '):not(.sidebar-menu-locked)').addClass('selected');
$('ul.sidebar-menu-1 li:not(:nth-child(' + cookieTestPlusTwo + '))').removeClass('selected');
$('.expand-collapse:eq(' + cookieTest + ')' ).show();
$('.expand-collapse:not(:eq(' + cookieTest + '))').hide();
};
// When clicking dashboard-module headers do stuff:
$('.dashboard-module h2:not(.limited h2):not(.tooltip h2)').click(function(index) {
var indexFoo = $('.dashboard-module h2:not(.tooltip h2)').index(this);
var indexPlusTwo = indexFoo + 2;
var indexCookie = indexFoo;
$.cookie("cookie", indexCookie, { expires: 7 });
$('.dashboard-module-content:eq(' + indexFoo + ')').toggleClass('hide-btn');
$('.dashboard-module-content:not(:eq(' + indexFoo + '))' ).removeClass('hide-btn');
$('ul.sidebar-menu-1 li:nth-child(' + indexPlusTwo + ')').addClass('selected');
$('ul.sidebar-menu-1 li:not(:nth-child(' + indexPlusTwo + '))').removeClass('selected');
$('.dashboard-module-content:eq(' + indexFoo + ') .expand-collapse').toggle('fast');
$('.dashboard-module-content:not(:eq(' + indexFoo + ')) .expand-collapse').hide('fast');
$('.dashboard-module-content:not(.limited)').each( function(){
if($(this).parent('.dashboard-module').find('.hide-btn').length == 0){
$(this).find('p.teaser').show();
}
else {
$(this).find('p.teaser').hide();
}
});
});
// When clicking sidebar list-items do stuff:
$('.sidebar-menu-1 li:not(.sidebar-menu-locked)').click(function(index) {
var indexFoo = ($('.sidebar-menu-1 li').index(this) - 1);
var indexPlusTwo = indexFoo + 2;
var indexCookie = indexFoo;
$.cookie("cookie", indexCookie, { expires: 7 });
$('.dashboard-module-content:eq(' + indexFoo + ')').toggleClass('hide-btn');
$('.dashboard-module-content:not(:eq(' + indexFoo + '))' ).removeClass('hide-btn');
$('ul.sidebar-menu-1 li:nth-child(' + indexPlusTwo + ')').addClass('selected');
$('ul.sidebar-menu-1 li:not(:nth-child(' + indexPlusTwo + '))').removeClass('selected');
$('.dashboard-module-content:eq(' + indexFoo + ') .expand-collapse').toggle('fast');
$('.dashboard-module-content:not(:eq(' + indexFoo + ')) .expand-collapse').hide('fast');
$('.dashboard-module-content:not(.limited)').each( function(){
if($(this).parent('.dashboard-module:not(.limited)').find('.hide-btn').length == 0){
$(this).find('p.teaser').show();
}
else {
$(this).find('p.teaser').hide();
}
});
});
至于现在,它在 FF 中都可以工作,但在 IE7+8 中却不行。但我的问题与其说是关于如何让它在 IE 中工作,不如说是关于你将如何完成这种任务?我怀疑我的 jQuery 并不完全是 DRY,但我该如何压缩它?
您将如何编写和组织您的代码?抱歉,如果这是一个过于宽泛和冗长的问题,但我真的很想知道经验丰富的 jQuery 设计师如何应对这样的挑战。
更新:多亏了 Tatu Ulmanen 的帮助,我才设法把它放在一起:http://timkjaerlange.com/foobar/jquery-test/index.html
最佳答案
打开模块
对于侧边栏链接 -> 内容关系,在侧边栏中使用与主要内容的 div 的 ID 相对应的 rel 标签,如下所示:
<ul id="sidebar">
<li><a href="#" rel="tab_1">Open tab 1</a></li>
<li><a href="#" rel="tab_2">Open tab 2</a></li>
<li><a href="#" rel="tab_3">Open tab 3</a></li>
</ul>
...
<div id="content">
<div class="module" id="tab_1"> ... </div>
<div class="module" id="tab_2"> ... </div>
<div class="module" id="tab_3"> ... </div>
</div>
然后在jQuery中,标签的改变很容易实现:
$('#sidebar a').click(function() {
$('#content div.module').hide();
$('#content div#'+$(this).attr('rel')).show();
return false;
});
模块标题
如果你想让模块的标题始终可见,你可以这样做:
<div id="content">
<div class="module" id="tab_1">
<h2>Module header</h2>
<p class="module_tools">
<a href="#" class="module_hide">Hide</a>
<a href="#" class="module_show">Show</a>
</p>
<div class="module_contents">
...
在 jQuery 中:
$('#sidebar a').click(function() {
var $visible_module = $('#content div#'+$(this).attr('rel'));
$('#content div.module div.module_contents').hide();
$('#content div.module div.module_contents a.module_hide').hide();
$('#content div.module div.module_contents a.module_show').show();
$visible_module.find('div.module_contents').show();
$visible_module.find('a.module_hide').show();
$visible_module.find('a.module_show').hide();
return false;
});
模块显示和隐藏
然后,为了在模块中实现显示按钮,我会“作弊”并让他们按下侧边栏中的相应按钮。
$('#content .module_show').click(function() {
$('#sidebar a[rel='+$(this).closest('div.module').attr('id')).click();
return false;
});
隐藏按钮很容易实现:
$('#content .module_hide').click(function() {
$(this).closest('div.module').find('div.module_contents').hide();
return false;
});
锁定模块
最后一件事是实现“锁定”功能。为此,我将向边栏的链接添加一个类,告诉当前选项卡处于非事件状态,然后根据该类修改模块:
<ul id="sidebar">
<li><a href="#" rel="tab_1">Open tab 1</a></li>
<li><a href="#" rel="tab_2" class="inactive">Open tab 2</a></li>
在 jQuery 中:
$('#sidebar a.inactive').each(function() {
var $target_module = $('#content div#'+$(this).attr('rel'));
// Remove the links alltogether
$target_module.find('.module_hide, .module_show').remove();
return false;
});
侧边栏的链接的点击事件也必须修改:
$('#sidebar a').click(function() {
if($(this).hasClass('inactive')) return false;
...
这涵盖了所有基础,不包括 cookie 保存。希望这能为您提供一些关于如何简化代码的指示。请注意,我还没有测试过任何这些,所以我不能保证它有效。如果您有不明白的地方,请随时提问。
请务必使用 CSS 样式来设置应用程序的初始状态,例如隐藏模块中的所有“隐藏”链接和 .module_contents,因为它们可能默认关闭。
关于javascript - 如何用jQuery实现这种高级接口(interface)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1898158/