【问题标题】:jquery selector logical AND?jquery选择器逻辑与?
【发布时间】:2011-02-24 08:54:25
【问题描述】:

在 jQuery 中,我试图仅选择 a 和 b 的文本值为 64 的挂载节点并相应地“测试”。如果不存在 64 和“测试”,我也想回退到 32。不过,我在下面的代码中看到的是,正在返回 32 安装而不是 64。

XML:


<thingses>
    <thing>
        <a>32</a> <-- note, a here is 32 and not 64 -->
        <other>...</other>
        <mount>sample 1</mount>
        <b>test</b>
    </thing>
    <thing>
        <a>64</a>
        <other>...</other>
        <mount>sample 2</mount>
        <b>test</b>
    </thing>
    <thing>
        <a>64</a>
        <other>...</other>
        <mount>sample 3</mount>
        <b>unrelated</b>
    </thing>
    <thing>
        <a>128</a>
        <other>...</other>
        <mount>sample 4</mount>
        <b>unrelated</b>
    </thing>
</thingses>

不幸的是,我无法控制 XML,因为它来自其他地方。

我现在做的是:


var ret_val = '';

$data.find('thingses thing').each(function(i, node) {
    var $node = $(node), found_node = $node.find('b:first:is(test), a:first:is(64)').end().find('mount:first').text();
    if(found_node) {
        ret_val = found_node;
        return;
    }

    found_node = $node.find('b:first:is(test), a:first:is(32)').end().find('mount:first').text();
    if(found_node) {
        ret_val = found_node;
        return;
    }

    ret_val = 'not found';
});

// expected result is "sample 2", but if sample 2's parent "thing" was missing, the result would be "sample 1"
alert(ret_val);

对于我正在使用的“:is”选择器:


    if(jQuery){
        jQuery.expr[":"].is = function(obj, index, meta, stack){
            return (obj.textContent || obj.innerText || $(obj).text() || "").toLowerCase() == meta[3].toLowerCase();
        };
    }

必须有比我的做法更好的方法。我希望我可以用“AND”或其他东西代替“,”。 :)

任何帮助将不胜感激。谢谢!

【问题讨论】:

    标签: jquery xml jquery-selectors xml-parsing


    【解决方案1】:

    为什么在find() 之后调用end()?我可能无法正确理解您的意图,但end() 会将您带回$node,因此后续的find("mount:first") 只会返回您的第一个mount 子节点。

    我错了吗?

    编辑

    此外,你为什么在所有things 上都使用.each?这样,您的 ret_value 实际上将获得符合 64-if-not-then-32 条件的 last thing 的 mount 值。

    如果你要选择第一个64/testthing,如果没有,那么第一个32/test,那何乐而不为你只是明确地写这个?

    var ret_value = $data.find( "thingses > thing:has( a:is(64) ):has( b:is(test) ) > mount" ).text();
    if ( !ret_value )
        ret_value = $data.find( "thingses > thing:has( a:is(32) ):has( b:is(test) ) > mount" ).text();
    

    您可以封装那个长查询以使代码更具可读性:

    function findByAandB( data, a, b ) {
        return data.find( "thingses > thing:has( a:is(" + a + ") ):has( b:is(" + b + ") ) > mount" ).text();
    }
    
    var ret_value = findByAandB( 64, "test" ) || findByAandB( 32, "test" );
    

    我是否误解了您的需求?因为我有点困惑:-)

    【讨论】:

    • 嗨,是的,我使用 end() 返回到 $node,这样我就可以获得那个“东西”的挂载文本值。我认为这相当于使用 .siblings('mount').text()。
    • 不,不是。 end() 实际上取消了您的最后一个查询转换。所以$("a").find("b").end() 等价于$("a")
    • 嗨,谢谢,我没有意识到我可以链:有这样的。我会试一试的!
    • :has 本质上是一个过滤器,就像您的 :is 一样。您可以一个接一个地应用任意数量的过滤器。
    • 成功了!像这样重用它的好主意。非常感谢。
    【解决方案2】:

    这似乎对我有用:

    var el = $('thingses thing')
        .has('b:contains("test")')
        .has('a:contains(64)');
    if(!el.length) 
        el = $('thingses thing')
            .has('b:contains("test")')
            .has('a:contains(32)');
    alert(el.find('mount:first').text());
    

    【讨论】:

    • 嘿,什么...?这与我的回答有何不同?
    • 这不是真的......当我开始打字时没有任何回应,而当我完成时你的回应就在那里(在那之后我清理了几次格式)。看到另一种编码风格永远不会有什么坏处,我希望你会得到绿色的复选框。
    【解决方案3】:

    各种想法:

    • 使用同级选择器 (Hierarchy selectors in jQuery)
      b 可以在 a 之前或之后,否则您可以保留一半的选择器

      find('b:first:is(test) ~ a:first:is(64), a:first:is(64) ~ b:first:is(test)')

    • 找到一个然后返回并找到另一个。我想它可能很丑

      find('b:first:is(test)).parent().find('a:first:is(64)')

    • custom jQuery selectors 可以接受参数,因此您可以编写 :allAtOnce 选择器:)

    【讨论】:

      猜你喜欢
      • 2011-01-24
      • 1970-01-01
      • 2011-05-23
      • 2017-01-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-03-15
      • 1970-01-01
      相关资源
      最近更新 更多