7

在这篇文章jQuery 表排序(github 链接:https ://github.com/padolsey/jQuery-Plugins/blob/master/sortElements/jquery.sortElements.js )之后,我成功地对列进行了排序,但是它在rowspan 的情况:例如这样的情况

 Grape      3,096,671M
            1,642,721M
 Apple      2,602,750M
            3,122,020M

当我单击第二列时,它会尝试排序

 Apple      2,602,750M
            1,642,721M
 Grape      3,096,671M
            3,122,020M

预期的结果应该是它应该只在每个行跨度内排序

 Grape      1,642,721M
            3,096,671M
 Apple      2,602,750M
            3,122,020M

或者

 Grape      3,096,671M
            1,642,721M
 Apple      3,122,020M
            2,602,750M

)

因此,如您所见,其中任何一个都不正确,请任何 jQuery 大师帮我解决这个问题。这是我的代码

var inverse = false;
function sortColumn(index){
    index = index + 1;
    var table = jQuery('#resultsTable');
    table.find('td').filter(function(){
        return jQuery(this).index() == index;
    }).sortElements(function(a, b){
        a = convertToNum($(a).text());
        b = convertToNum($(b).text());

        return (
            isNaN(a) || isNaN(b) ?
            a > b : +a > +b
            ) ?
        inverse ? -1 : 1 :
        inverse ? 1 : -1;
    },function(){
        return this.parentNode;
    });
    inverse = !inverse;
}
function convertToNum(str){
    if(isNaN(str)){
        var holder = "";
        for(i=0; i<str.length; i++){                                
            if(!isNaN(str.charAt(i))){
                holder += str.charAt(i);
            }
        }
        return holder;
    }else{
        return str;
    }
}

问题:

1.如何使用rowspan对此进行排序。ROWSPAN 的数量并不总是相同的。上面的例子 Grape 和 Apple 的行跨度都是 2,但情况并非总是如此。

2.任何人都可以解释这个语法:

 return (
            isNaN(a) || isNaN(b) ?
            a > b : +a > +b
            ) ?
        inverse ? -1 : 1 :
        inverse ? 1 : -1;

所以我可以看到,如果 a 或 b 不是数字,则进行字符串比较,否则进行数字比较,但我不明白

inverse ? -1 : 1 :
inverse ? 1 : -1;

测试用例

<table id="resultsTable">
        <thead>
            <tr>
                <th>Fruit</th>
                <th onclick="sortColumn(1)">Quantity</th>
                <th onclick="sortColumn(2)">Rate</th>
            </tr>
        </thead>
        <tbody>
            <tr>
                <td rowspan="4">Grape</td>
                <td>15</td>
                <td>5</td>
            </tr>
            <tr>
                <td>4</td>
                <td>2</td>
            </tr>
            <tr>
                <td>88</td>
                <td>1</td>
            </tr>
            <tr>                    
                <td>11</td>
                <td>3</td>
            </tr>
            <tr>
                <td rowspan="3">Melon</td>
                <td>21</td>
                <td>2</td>
            </tr>
            <tr>
                <td>2</td>
                <td>0</td>
            </tr>
            <tr>
                <td>35</td>
                <td>1</td>
            </tr>
            <tr>
                <td rowspan="6">Melon</td>
                <td>24</td>
                <td>5</td>
            </tr>
            <tr>
                <td>66</td>
                <td>2</td>
            </tr>
            <tr>
                <td>100</td>
                <td>4</td>
            </tr>
            <tr>
                <td>21</td>
                <td>1</td>
            </tr>
            <tr>
                <td>65</td>
                <td>3</td>
            </tr>
            <tr>
                <td>2</td>
                <td>0</td>
            </tr>
        </tbody>
 <table>
4

2 回答 2

3

代码工作的条件:

  • 包含tds 的列rowspan必须都在表格的左侧
  • td这些列中的所有s必须有一个rowspan,即使它是 1
  • 要排序的行组由这些列的最右边组成(但可以轻松更改)

jsFiddle:http: //jsfiddle.net/5GrAC/77/

var inverse = false;

function sortColumn(index) {
    var trs = $('#resultsTable > tbody > tr'),
        nbRowspans = trs.first().children('[rowspan]').length,
        offset = trs.first().children('[rowspan]').last().offset().left;

    var tds = trs.children('[rowspan]').each(function() {
        $(this).data('row', $(this).parent().index());
        $(this).data('column', $(this).index());
        $(this).data('offset', $(this).offset().left)
    }).each(function() {
        if($(this).data('offset') != offset)
            return;

        var rowMin = $(this).data('row'),
            rowMax = rowMin + parseInt($(this).attr('rowspan'));

        trs.slice(rowMin, rowMax).children().filter(function() {
            return $(this).index() == index + $(this).parent().children('[rowspan]').length - nbRowspans;
        }).sortElements(function(a, b) {
            a = convertToNum($(a).text());
            b = convertToNum($(b).text());

            return (
                isNaN(a) || isNaN(b) ?
                a > b : +a > +b
                ) ?
            inverse ? -1 : 1 :
            inverse ? 1 : -1;
        }, function() {
            return this.parentNode;
        });
    });

    var trs = $('#resultsTable > tbody > tr');
    tds.each(function() {
        if($(this).parent().index() != $(this).data('row'))
            $(this).insertBefore(trs.eq($(this).data('row')).children().eq($(this).data('column')));
    });

    inverse = !inverse;
}

快速解释:

  • 找到所有tdsrowspan
  • td保存这些s的位置,包括左偏移
  • 这些tds 被它们的原始过滤,offset只与最右边的一起工作
  • tr与每个保留相关的 std使用所需列进行排序
  • 如有必要,所有tdsrowspan最终都会移回其原始位置

关于问题2,我只会说完成bartlaarhoven的回答,代码也可以这样写:

return (
        (isNaN(a) || isNaN(b) ? a > b : +a > +b) ? 1 : -1
    ) * (inverse ? -1 : 1);

您可以轻松阅读inverse用于反转结果的内容。

于 2012-10-18T09:34:32.337 回答
2

考虑问题1,试试这个代码:

var inverse = false;
var curRowSpan = 0;
var curIndex = 0;
var doRowSpan = false;
function sortColumn(index){
    index = index + 1;
    var table = jQuery('#resultsTable');
    table.find('td').filter(function() {
        var result = false;
        // if it is a column before the sorting column, watch the rowSpan
        if (curRowSpan == 0 && jQuery(this).index() < index && jQuery(this).attr("rowspan") > 1) {
            curRowSpan = jQuery(this).attr("rowspan");
            doRowSpan = true;
            // we are not in the sorting column so we can safely continue
            continue;
        }

        if(!doRowSpan) curIndex = index - (curRowSpan?1:0);
        else curIndex = index;

        if(jQuery(this).index() == curIndex) {
            // we are at the sorting column
            if(curRowSpan > 0) {
                curRowSpan--;
            }
            // set this to false for the following row
            doRowSpan = false;
            result = true;
        }

        return result;
    }).sortElements(function(a, b){
        a = convertToNum($(a).text());
        b = convertToNum($(b).text());

        return (
            isNaN(a) || isNaN(b) ?
            a > b : +a > +b
        ) ?
            inverse ? -1 : 1 :
            inverse ? 1 : -1;
        },function(){
            return this.parentNode;
        });
        inverse = !inverse;
    }
    function convertToNum(str){
        if(isNaN(str)){
            var holder = "";
            for(i=0; i<str.length; i++){                                
                if(!isNaN(str.charAt(i))){
                    holder += str.charAt(i);
                }
            }
            return holder;
        }else{
            return str;
        }
    }

考虑问题 2;让我们扣除它的来源。首先,我们要检查是否 a > b,并且,正如您已经正确看到的,我们在字符串比较和数字比较之间进行了区分。

然后我们将简单地给出:

return (
        isNaN(a) || isNaN(b) ?
        a > b : +a > +b
        ) ? 1 : -1;

这将检查 a > b (字符串方式或数字方式),然后在 true 时返回 1,在 false 时返回 -1。

现在我们插入inverse参数,它应该反转结果。这意味着如果 inverse == true,则 1 变为 -1 并且 -1 变为 1。在代码中,这段粗体文本将替换每次出现的1withinverse ? -1 : 1和每次出现的-1with inverse ? 1 : -1。这正是结果代码中所做的。

更新doRowSpan在代码中添加,因为如果我们在<tr>包含行跨度的位置,它不应该调整索引td

于 2012-10-17T19:04:12.013 回答