Javascript jQuery sortColumns插件:如何使用rowspan正确排序

Javascript jQuery sortColumns插件:如何使用rowspan正确排序,javascript,jquery,html,Javascript,Jquery,Html,在这篇文章(github链接:)之后,我成功地对列进行排序,但是它在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

在这篇文章(github链接:)之后,我成功地对列进行排序,但是它在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

)

所以 正如您所看到的,这是不正确的,请任何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;
    }
}
所以我可以看出,如果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>

果
量
比率
葡萄
15
5.
4.
2.
88
1.
11
3.
甜瓜
21
2.
2.
0
35
1.
甜瓜
24
5.
66
2.
100
4.
21
1.
65
3.
2.
0

考虑到问题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;
        }
    }
这将检查a>b(按字符串或按数字),然后返回1为真,返回-1为假

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


更新:在代码中添加了
doRowSpan
,因为如果我们在
中,包含行span-
td

代码工作的条件,则不应调整索引:

  • 包含
    td
    s和
    rowspan
    的列必须全部位于表的左侧
  • 这些列中的所有
    td
    s必须有
    行span
    ,即使它是1
  • 要排序的行组由这些列中最右边的列组成(但很容易更改)
jsFiddle:

快速解释:

  • 使用
    rowspan查找所有
    td
    s
  • 保存这些
    td
    s的位置,包括左偏移
  • 这些
    td
    s通过其原始
    offset
    进行过滤,以仅与最右边的
    一起使用
  • 与每个保留的
    td
    相关的
    tr
    使用所需列进行排序
  • 如有必要,带
    rowspan
    的所有
    td
    s将最终移回其原始位置

关于问题2,我将只通过以下方式完成bartlaarhoven的回答:代码也可以按如下方式编写:

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

您可以很容易地看到,
inverse
用于反转结果。

@Newbo.O:它应该只在每个行范围内排序。我已经用预期结果更新了我的问题。仅在行范围内排序或:对每个行范围组进行排序,然后根据第一个值对组进行排序?非常感谢。当我插入你的代码时,我得到了这个javascript错误
未捕获的语法错误:非法的continue语句
。你能检查一下吗,我用
http://ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js
因为我传入索引的方式,我需要index=index+1,但是,在您的情况下,请将其取出。另外,我使用了你的代码(没有continue),但是这个表坏了,我把我用来测试的表放在我的问题中,你能看一下吗。非常感谢你。我也在调查此事。谢谢你这么说,因为我通过索引的方式,我需要
index=index+1
,但是,如果是你的情况,请把它拿出来。还有,我用了你的代码,但是表坏了,我把我用来测试的表放在我的问题里,你能看一下吗。非常感谢你。我也在调查此事。谢谢我的错误,我有时把一个
td
移到
thead
。。。我已经更新了我的答案来解决这个问题。我还用您的数据示例创建了一个JSFIDLE(我没有放置任何CSS,所以它有点难看,但它可以工作),谢谢您,您太棒了,还有一件事。mmidle块(中间的
块),其排序与其他所有块的排序相反。请你看一下好吗。非常感谢:DI对代码进行了一点优化(搜索和筛选太多了),应该可以更好地处理大型表。答案已更新,因此可以处理左侧更多的行间距。仍然有条件可以使用代码,但我认为很难找到更通用的解决方案^^
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;
        }
    }
return (
        isNaN(a) || isNaN(b) ?
        a > b : +a > +b
        ) ? 1 : -1;
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;
}
return (
        (isNaN(a) || isNaN(b) ? a > b : +a > +b) ? 1 : -1
    ) * (inverse ? -1 : 1);