任何人都可以帮助我缩短这个荒谬的长选择器吗?

时间:2012-08-05 04:02:44

标签: javascript jquery jquery-selectors

编辑:跳过结束以更好地解释我所追求的内容,thx

我有大约以下的html(这只是摘录),其中有一个嵌套的章节组织:

<span class="chapter Art" id="00034">
  <li><span class="chapterheading">Art<span>some stuff</span></li>
  <ul>
    <span class="chapter" id="00035">
      <li><span class="chapterheading selectednode">Sound</span><span>more stuff</span></li>
      <div class="idea">even more stuff</div>
    </span>
  </ul>
</span>

现在我希望使用javascript只显示紧接在下面的章节标题,并且紧接在类'idea'的div下面,以便看到任何'想法',你必须点击它的直接父章。

花了大约三个小时后(因为我对jquery有点绿,我花了一段时间才意识到子选择器真的如何工作),我想出了一个非常复杂的查询,它可以满足我的需求。显示相关节点(假设它们在运行此代码之前被隐藏):

t.find("li > *, ul > .chapter, ul > .chapter > li, ul > .chapter > li *, > .idea, > .idea *").show();

其中't'是最近点击的节点,它具有类'selectednode'(编辑:是该节点的父节点的父节点)。

那么在这里表达我需要的东西会有更短的方式吗?

编辑:以下是一个更大的代码片段,需要很多行李。寻找评论“隐藏相同深度的兄弟姐妹的孩子们。”

我已经对它进行了一些修剪,但它没有做我想做的事情:我无法让它显示只是下面的直接章节和想法,它显示了一切。

function toggleNode(node, value) {
    //_("setting " + nv(node) + " to " + value + "\n");
    $(node).toggleClass("selectednode", value);
    if($(node).hasClass("selectednode") == true)
    selectednode = node;
    if($(selectednode).hasClass("selectednode") == false) // is this check really necessary?
    selectednode = 0;
}


function zoomTo(node, select) {
    var zoom, oldzoom, depth, t;
    //_("zoomTo(" + (node ? $(node).text() : "0") + ", " + select + ")");
    oldzoom = zoomednode;
    if(node != zoomednode) {
    savedepth = t = depth = $(node).parents("ul").length;
    if(!zoomednode)
        zoomednode = topChapter;
    if(!node)
        node = topChapter;
    /* capture values */
    var sz;
    var capp = cBaseSz.slice((sz = parseFloat(cBaseSz)).length);
    /* end capture */
    zoom = zoomnum = sz;
    while(--t > 0) {
            zoomnum = (zoom *= 1.15);
    }
    //_("zoom: " + zoomnum +"\ncapp: " +capp);
    zoom  += capp;
    //_("zoom: " + zoomnum);
    depth -= $(zoomednode).parents("ul").length;
    if(depth < 0)
        depth *= -1;
    switch(select) {
    case 0:
    case false:
    default:
        break;
    case true:
    case 1:
        toggleNode(zoomednode, false);
        toggleNode(zoomednode = node, true);
        break;
    case 2:
        toggleNode(zoomednode, false);
            zoomednode = 0;
    }

    /* Handle showing/hiding */

    if(1) {
        var hide;
        t = ($(selectednode) || $(".chapterheading:first"));
        _("t.text():" + t.text());
        t = t.parent().parent();
        _("isclass: " + t.attr("class"));
        var prs = $(t).parents(".chapter");
        prs = $(prs)[0] || t;
        hide = $(prs).siblings(".chapter");
        _("topparent: " + $(prs).text().slice(0,80));
        $(hide).each( function() { {
        _(($(this).html()||$(this).text()).slice(0, 80));
        }});
        $("li *, > ul, > idea", t).show();
        //t.siblings().show();
        //t.siblings().find().hide();
        //hide.children(".chapterheading").find().show();
        //showall(t.find("li *, ul > .chapter > li *"));

        // Hide deeper children of this chapter (t) 
//      $(t).find("ul *:not(ul > .chapter > li, ul > li *)").hide();
//      t.find("li > *, ul > .chapter, ul > .chapter > li, ul > .chapter > li *, > .idea, > .idea *").show();
        // Show immediate children of this chapter (t)
        //$(t).find("> li *, ul > .chapter").show();
       // t.find(".chapterheading, .ideacount").show();
        //$(hide).children().find(":not(.chapterheading, .ideacount)").hide();



        // Hide children of sibling chapters of the same depth.
        $("ul > .chapter", t).hide();
        // Hide children of siblings of the top-most parent chapter of the selected chapter.
        $("ul > .chapter, ul > .chapter .chapter", hide).hide();
        // Show the selected chapter
        $("ul > .chapter, ul > chapter .chapter", t.parent()).show();
        }

    //////////////////////////////
     // old version below, but keeping for reference
    else {
    var showzoom = 1, showselect = 1, showidea = 1, seldepth, zdepth, showlist, hidelist = {};
    /* This is the 'brute force' way of doing it, horribly inefficient */
    if(zoomednode)
        zdepth = $(zoomednode).parents(".chapter").length;
    if(selectednode)
        seldepth = $(selectednode).parents(".chapter").length;
    else
        seldepth = zdepth;
    if(!seldepth)
        seldepth = zdepth = 0;
    _("seldepth: " + seldepth + "\nzdepth: " + zdepth);
    (showlist=$(".chapter").filter( function() {
        if($(this).parents(".chapter").length < (zdepth+showzoom))
        return true;
        else {
        hidelist = $(hidelist).add(this);
        return false;
        }
    }));
    //    hidelist = $("all").not(showlist);
    if(hidelist)
        _("hidelist size: " + hidelist.length);
    _("showlist size: " + showlist.length);
    $(showlist).show()/*.not(hidelist)*/;
    if(hidelist && hidelist.length) {
        //_("Hiding " + $(hidelist).length + " elements.");
        $(hidelist).hide();
    }
    }
    /* End showing/hiding */

    /* Begin animating */
    $("#contents").animate({ fontSize: zoom }, {duration: 0, queue: false });
    $("html").animate(
        { scrollTop: $(node).offset().top - topAdjust }, {duration: 60+60*depth, queue: false }, 0);
    $(window).scrollLeft($(node).offset().left - leftAdjust);
    } else {

    zoomTo(0, 1 + (selectednode == zoomednode));
    }
}


function setupEvents() {
    $("#contents .chapterheading").click( function() {  _("\n-- -- -- CLICK -- -- --\n-- -- -- -- -- -- -- --\n"), zoomTo(this, true); });
}

编辑:为了进一步参考,标记具有以下类别(递归表示):

<ul> <!-- A: chapter heading list -->
  <span class="chapter">
    <li><span class="chapterheading">Title</span></li>
    <!-- 0 or more of the following --> <div class="idea"><!-- more stuff --></div>
    <!-- 0 or more of A: chapter heading list -->
  </span>
</ul>

并且,变量't'指向类“selectednode”的地方也将被追加,这是我希望发生以下情况的地方:

  1. 显示所有直接的子'ul'元素,这也意味着该章的标题。但是不要在下面显示任何内容。
  2. 隐藏所有兄弟章节所选章节的内容。
  3. 隐藏所选章节的显示内容,以显示所选章节中不属于祖先的所有最顶层章节。

3 个答案:

答案 0 :(得分:2)

重构HTML以使其有效。我的建议是:

<div id="toc">
   <h2>Table of Contents</h2>
   <ul>
      <li id="00034" class="art">
         <span class="chapterheading">Title</span>
         <!-- more stuff -->
         <div class="idea"> ... </div>
         ...
         <ul>
            <li id="00035">
               <span class="chapterheading selected">Subtitle</span>
            </li>
            ...
         </ul>
      </li>
      <li>
         <span class="chapterheading">Second Title</span>
         ...
      </li>
      ...
   </ul>
</div>

这不使用chapter类,它只是假设li中的所有#toc元素代表一个章节。

使用这种结构,构建的DOM(应用所有选择器等,您可以在开发人员控制台中检查它)看起来与HTML标记完全相同。在您的代码中,span元素中的ul标记很可能会移动到li个项目中。

现在,要隐藏章节后面的所有元素,我们使用此代码CSS代码:

#toc li > * {
    display: none;
}

但如果选择了li则显示它们:

#toc li > span.chapterheading, #toc li.selected > * {
    display: block;
}

使用Javascript,我们现在只需根据点击次数移动selected类:

$(document).ready(function() {
    $("#toc").on("click", "span.chapterheading", function(ev) {
        $(this).closest("li")
          .addClass("selected")
          .siblings().removeClass("selected");
    });
});

答案 1 :(得分:1)

很难说你正在使用什么,因为你没有显示足够的代码。

基于您的标记模式以及我认为您在一行JavaScript之外所做的事情,我觉得这可能对您有用:

$( '.chapterheading' ).click( function(){
  var t = $( this );
  //I assume you are doing other stuff with t...
  t.parent().next().show();
});

演示:http://jsfiddle.net/US4Nr/

答案 2 :(得分:0)

另一种类型的列表更适合此类问题 - 即定义列表<dl>以及定义词<dt>和定义描述<dd>

HTML:

<div id="toc">
    <h2>Table of Contents</h2>
    <dl>
        <dt id="00034">Title 00034</dt>
        <dd class="text">text 00034</dd>
        <dd class="idea">idea 00034</dd>
        <dd class="sub">
            <dl>
                <dt id="00035">Subtitle 0035</dt>
                <dd class="text">text 00035</dd>
                <dd class="idea">idea 00035</dd> 
            </dl>
        </dd>
    </dl>
    <dl>
        <dt id="00036">Title 00036</dt>
        <dd class="text">text 00036</dd>
        <dd class="idea">idea 00036</dd> 
    </dl>
</div>

和javascript:

$("#toc dt").on('click', function() {
    $(this).closest("dl")
        .children(".idea").hide().end()
        .children(".text, .sub").toggle().end()
        .siblings().find("dd").hide();
});

$("#toc dd.text").on('click', function() {
    $(this).closest("dl").children(".idea").toggle();
});

<强> DEMO

所有控制都由javascript直接执行。 DEMO中的所有CSS都是用于外观,而不是用于隐藏/显示。

可能不是您想要的,特别是关于事件处理程序如何附加,但应该让您知道如何处理它。