You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

点击表格列标题无法排序问题排查求助

表格列排序功能无响应问题排查与修复

问题描述

尝试实现表格列点击排序(升序/降序切换),但点击列标题后无任何反应,无法完成排序,找不到错误原因。


相关代码

前端HTML/JavaScript代码

<!DOCTYPE html>
<html>
<head>
    <title>Tabella Interattiva</title>
    
<style>
    .....
</style>

<script>
function toggleView() {
    var tableView = document.getElementById("tableView");
    var gridView = document.getElementById("gridView");
    var toggleButton = document.getElementById("toggleButton");
    var tableContainer = document.querySelector(".table-container");

    if (tableView.style.display === "none") {
        tableView.style.display = "block";
        gridView.style.display = "none";
        toggleButton.textContent = "Visualizza come griglia";
        tableContainer.classList.remove("grid-mode");
    } else {
        tableView.style.display = "none";
        gridView.style.display = "flex";
        toggleButton.textContent = "Visualizza come tabella";
        tableContainer.classList.add("grid-mode");
    }
}

function sortTable(columnHeader, column) {
    var table = document.getElementById("tableView");
    var rows = Array.from(table.getElementsByTagName("tr"));
    var switching = true;
    var dir = 1;

    if (columnHeader.classList.contains("asc")) {
        columnHeader.classList.remove("asc");
        columnHeader.classList.add("desc");
        dir = -1;
    } else if (columnHeader.classList.contains("desc")) {
        columnHeader.classList.remove("desc");
        columnHeader.classList.add("asc");
    } else {
        columnHeader.classList.add("asc");
    }

    var headerColumns = Array.from(table.getElementsByClassName("table-header")[0].getElementsByTagName("th"));
    headerColumns.forEach(function (col) {
        if (col !== columnHeader) {
            col.classList.remove("asc", "desc");
        }
    });

    if (table.classList.contains("grid-mode")) {
        var gridItems = Array.from(document.getElementsByClassName("grid-item"));
        sortGridItems(gridItems);
    } else {
        sortTableRows(rows, column, columnHeader.classList.contains("asc") ? "asc" : "desc");
    }
}

function sortTableRows(rows, column, order) {
    var switching = true;
    var dir = order === "asc" ? 1 : -1;

    while (switching) {
        switching = false;
        for (var i = 1; i < rows.length - 1; i++) {
            var x = rows[i].getElementsByTagName("td")[column].textContent;
            var y = rows[i + 1].getElementsByTagName("td")[column].textContent;
            if (dir * x.toLowerCase() > dir * y.toLowerCase()) {
                rows[i].parentNode.insertBefore(rows[i + 1], rows[i]);
                switching = true;
            }
        }
    }
}

function sortGridItems(items) {
    var sortedItems = Array.prototype.slice.call(items).sort(function (a, b) {
        var sortOrderA = parseInt(a.getAttribute("data-sort-order"));
        var sortOrderB = parseInt(b.getAttribute("data-sort-order"));
        return sortOrderA - sortOrderB;
    });

    var gridView = document.getElementById("gridView");
    while (gridView.firstChild) {
        gridView.removeChild(gridView.firstChild);
    }

    for (var i = 0; i < sortedItems.length; i++) {
        gridView.appendChild(sortedItems[i]);
    }
}

</script>

</head>
<body>
    <h1>Tabella Interattiva</h1>
    <div class="table-container grid-mode">
    <div class="centered-form">
        <form method="POST" action="/">
            <input type="text" name="search_term" placeholder="Filtro per artista, brano o genere">
            <button type="submit">Cerca</button>
        </form>
    </div>
    
    <div class="table-container">
        <div style="margin-bottom: 20px;">
            <button id="toggleButton" class="toggle-button" type="button" onclick="toggleView()">Visualizza come griglia</button>
        </div>
        <table id="tableView">
            <thead>
                <tr class="table-header">
                    
                    
                    <th onclick="sortTable(this, 0)" class="{% if sort_column == 'artist' %}{{ sort_order }}{% endif %}">Artista</th>
                    <th onclick="sortTable(this, 1)" class="{% if sort_column == 'name' %}{{ sort_order }}{% endif %}">Brano</th>
                    <th onclick="sortTable(this, 2)" class="{% if sort_column == 'genres' %}{{ sort_order }}{% endif %}">Generi</th>

                </tr>
            </thead>
            <tbody>
                {% for track in tracks %}
                <tr>
                    <td>{{ track.artist }}</td>
                    <td>{{ track.name }}</td>
                    <td>{{ track.genres }}</td>
                </tr>
                {% endfor %}
            </tbody>
        </table>

        <div id="gridView" class="grid-view">
            <div class="grid-column">
                {% for track in tracks %}
                <div class="grid-item" data-sort-order="{{ loop.index }}">
                    <img src="{{ track.image_url }}" alt="Locandina">
                    <div class="grid-item-content">
                        <p><strong>Artista: {{ track.artist }}</strong></p>
                        <p><strong>Brano: {{ track.name }}</strong></p>
                        <div class="partner-item">
                            <h4>Partner:</h4>
                            <p>Cerca informazioni su Wikipedia, ad esempio</p>
                            <a href="https://it.wikipedia.org/wiki/{{ track.name }}" target="_blank">
                                <button class="wikipedia-button">Cerca su Wikipedia</button>
                            </a>
                        </div>
                        <p>Generi: {{ track.genres }}</p>
                    </div>
                </div>
                {% endfor %}
            </div>
        </div>
    </div>
</body>
</html>

后端Flask核心代码

def sort_tracks(tracks, column, order):
    if column == 'artist':
        tracks.sort(key=lambda x: x['artist'], reverse=(order == 'desc'))
    elif column == 'name':
        tracks.sort(key=lambda x: x['name'], reverse=(order == 'desc'))
    elif column == 'genres':
        tracks.sort(key=lambda x: x['genres'], reverse=(order == 'desc'))

    return tracks

def get_liked_tracks():
    liked_tracks = []

    # Recupera gli ultimi 5 brani a cui hai messo "Mi piace"
    results = sp.current_user_saved_tracks(limit=10)

    for item in results['items']:
        track = item['track']
        artists = [artist['name'] for artist in track['artists']]

        # Recupera i generi per ogni artista
        genres = []
        for artist in track['artists']:
            artist_info = sp.artist(artist['id'])
            genres.extend(artist_info['genres'])

        liked_tracks.append({
            'artist': ', '.join(artists),
            'name': track['name'],
            'genres': ', '.join(genres),
            'image_url': track['album']['images'][0]['url']  # URL dell'immagine della locandina
        })

    return liked_tracks

@app.route('/', methods=['GET', 'POST'])
def index():
    search_term = request.form.get('search_term', '')
    tracks = get_liked_tracks()
    if search_term:
        tracks = filter_tracks(tracks, search_term)

    sort_column = request.args.get('sort_column', session.get('sort_column'))
    sort_order = request.args.get('sort_order', session.get('sort_order'))

    if sort_column is not None and sort_order is not None:
        tracks = sort_tracks(tracks, sort_column, sort_order)
        session['sort_column'] = sort_column
        session['sort_order'] = sort_order

    return render_template('index.html', tracks=tracks, sort_column=sort_column, sort_order=sort_order)

def filter_tracks(tracks, search_term):
    if not search_term:
        return tracks

    filtered_tracks = []
    for track in tracks:
        if (
            search_term.lower() in track['artist'].lower()
            or search_term.lower() in track['name'].lower()
            or search_term.lower() in track['genres'].lower()
        ):
            filtered_tracks.append(track)

    return filtered_tracks

问题根源

  1. 字符串比较逻辑错误:sortTableRows中使用dir * x.toLowerCase(),字符串与数字相乘会得到NaN,导致比较逻辑完全失效。
  2. 行选择范围错误:rows = Array.from(table.getElementsByTagName("tr"))包含了表头行,排序时会打乱表格结构。
  3. 网格排序未关联列规则:sortGridItems仅按初始的data-sort-order排序,未响应点击列的排序需求。
  4. 容器类判断错误:grid-mode类在父容器.table-container上,而非表格元素本身,导致视图模式判断失效。

修复方案

前端代码修改

1. 修复表格行排序逻辑

function sortTableRows(rows, column, order) {
    // 仅选取tbody内的数据行,排除表头
    const tbodyRows = rows.filter(row => row.parentNode.tagName === 'TBODY');
    const dir = order === "asc" ? 1 : -1;

    // 使用localeCompare进行字符串排序,支持多语言
    tbodyRows.sort((a, b) => {
        const x = a.getElementsByTagName("td")[column].textContent.trim().toLowerCase();
        const y = b.getElementsByTagName("td")[column].textContent.trim().toLowerCase();
        return dir * x.localeCompare(y);
    });

    // 将排序后的行重新插入tbody
    const tbody = document.querySelector('#tableView tbody');
    tbodyRows.forEach(row => tbody.appendChild(row));
}

2. 修正sortTable函数的核心逻辑

function sortTable(columnHeader, column) {
    var table = document.getElementById("tableView");
    // 直接获取tbody内的行,避免包含表头
    var rows = Array.from(table.querySelector("tbody").getElementsByTagName("tr"));

    // 切换排序状态
    if (columnHeader.classList.contains("asc")) {
        columnHeader.classList.remove("asc");
        columnHeader.classList.add("desc");
    } else if (columnHeader.classList.contains("desc")) {
        columnHeader.classList.remove("desc");
        columnHeader.classList.add("asc");
    } else {
        columnHeader.classList.add("asc");
    }

    // 清除其他列的排序状态
    var headerColumns = Array.from(table.getElementsByClassName("table-header")[0].getElementsByTagName("th"));
    headerColumns.forEach(function (col) {
        if (col !== columnHeader) {
            col.classList.remove("asc", "desc");
        }
    });

    const currentOrder = columnHeader.classList.contains("asc") ? "asc" : "desc";
    // 修正视图模式判断:检查父容器的类
    if (table.closest(".table-container").classList.contains("grid-mode")) {
        sortGridItems(column, currentOrder);
    } else {
        sortTableRows(rows, column, currentOrder);
    }
}

3. 修复网格排序逻辑,关联点击列

function sortGridItems(column, order) {
    const dir = order === "asc" ? 1 : -1;
    const gridItems = Array.from(document.getElementsByClassName("grid-item"));
    
    // 根据点击的列提取对应内容排序
    const sortedItems = gridItems.sort((a, b) => {
        let textA, textB;
        switch(column) {
            case 0: // 艺术家列
                textA = a.querySelector('strong').textContent.replace('Artista: ', '').trim().toLowerCase();
                textB = b.querySelector('strong').textContent.replace('Artista: ', '').trim().toLowerCase();
                break;
            case 1: // 歌曲列
                textA = a.querySelectorAll('strong')[1].textContent.replace('Brano: ', '').trim().toLowerCase();
                textB = b.querySelectorAll('strong')[1].textContent.replace('Brano: ', '').trim().toLowerCase();
                break;
            case 2: // 流派列
                textA = a.querySelector('p:last-child').textContent.replace('Generi: ', '').trim().toLowerCase();
                textB = b.querySelector('p:last-child').textContent.replace('Generi: ', '').trim().toLowerCase();
                break;
            default:
                return 0;
        }
        return dir * textA.localeCompare(textB);
    });

    const gridColumn = document.querySelector("#gridView .grid-column");
    while (gridColumn.firstChild) {
        gridColumn.removeChild(gridColumn.firstChild);
    }

    sortedItems.forEach(item => gridColumn.appendChild(item));
}

后端优化(可选,后端排序方案)

若数据量较大,建议改用后端排序,修改前端列标题点击事件:

<th onclick="window.location.href='/?sort_column=artist&sort_order=' + (this.classList.contains('asc') ? 'desc' : 'asc')" 
    class="{% if sort_column == 'artist' %}{{ sort_order }}{% endif %}">Artista</th>
<th onclick="window.location.href='/?sort_column=name&sort_order=' + (this.classList.contains('asc') ? 'desc' : 'asc')" 
    class="{% if sort_column == 'name' %}{{ sort_order }}{% endif %}">Brano</th>
<th onclick="window.location.href='/?sort_column=genres&sort_order=' + (this.classList.contains('asc') ? 'desc' : 'asc')" 
    class="{% if sort_column == 'genres' %}{{ sort_order }}{% endif %}">Generi</th>

同时完善后端默认排序逻辑:

@app.route('/', methods=['GET', 'POST'])
def index():
    search_term = request.form.get('search_term', '')
    tracks = get_liked_tracks()
    if search_term:
        tracks = filter_tracks(tracks, search_term)

    # 设置默认排序规则
    sort_column = request.args.get('sort_column', session.get('sort_column', 'artist'))
    sort_order = request.args.get('sort_order', session.get('sort_order', 'asc'))

    tracks = sort_tracks(tracks, sort_column, sort_order)
    session['sort_column'] = sort_column
    session['sort_order'] = sort_order

    return render_template('index.html', tracks=tracks, sort_column=sort_column, sort_order=sort_order)

内容的提问来源于stack exchange,提问作者Super Sonic

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.16 01:47:01