javascript - 如何用jQuery实现这种高级接口(interface)?

标签 javascript jquery

我目前正在与我试图放在一起的界面进行一场激烈的战斗。我在 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/

相关文章:

javascript - 我真的应该在使用它们之前在 Javascript 中声明所有变量吗?

javascript - Ajax 响应作为 DOM 对象

javascript - 从不同范围访问 "this"

javascript - 在多个元素上设置路径点

jquery - jquery如何在下拉列表中添加值

javascript - 拆分每个大写字母,除非它前面有空格

php - 如何使用 .load() 根据引用 URL 加载特定内容 ID

javascript - 使用 Javascript 返回在 SVG 中单击的哪一段线

javascript - 类型错误 : Cannot read property 'startDate' of undefined

jquery - 如何将 Bootstrap 模式中的 <select> html 数据传递给 jquery