Ajax获取PHP端csv转的json数据并js前端排序与分页

html 复制代码
<?php
setlocale(LC_ALL, 'C'); //window:删除行首双斜杠

if($_GET["act"]=="list"){
$csvFile = 'book.csv'; // 文件路径:制表符分隔文件
$data = [];
if (($handle = fopen($csvFile, 'r')) !== false) {
    $header = fgetcsv($handle,0,"\t"); // 读取表头
    while (($row = fgetcsv($handle,0,"\t")) !== false) {
        $data[] = array_combine($header, $row); // 将表头与数据组合
    }
    fclose($handle);
}
header('Content-Type: application/json');
echo json_encode($data);
exit();
}
?>
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>数据表格</title>
<style>
.container {
    margin: 20px;
}

table {
    width: 100%;
    border-collapse: collapse;
    margin-bottom: 20px;
}

th, td {
    border: 1px solid #ddd;
    padding: 5px;
    text-align: left;
}

th {
    background-color: #f5f5f5;
    position: relative;
    padding-right: 25px;
    cursor: pointer;
}

.sort-arrows {
    position: absolute;
    right: 5px;
    top: 50%;
    transform: translateY(-50%);
    display: flex;
    flex-direction: column;
    line-height: 8px;
}

.arrow {
    font-size: 8px;
    color: #666;
}

.arrow.active {
    color: red;
}

.pagination {
    display: flex;
    gap: 10px;
    align-items: center;
    justify-content: center;
}

button {
    padding: 5px 10px;
    cursor: pointer;
}

select {
    padding: 5px;
}

tr:nth-child(even) {
    background-color: #f9f9f9;
}

tr:hover {
    background-color: #f5f5f5;
}
</style>
</head>
<body>
    <div class="container">
        <table id="dataTable">
            <thead>
                <tr id="headerRow">
                    <!-- 表头将由JS动态生成 -->
                </tr>
            </thead>
            <tbody id="tableBody">
                <!-- 数据行将由JS动态生成 -->
            </tbody>
        </table>
        <div class="pagination">
            <button id="firstPage">首页</button>
            <button id="prevPage">上一页</button>
            <select id="pageSelect"></select>
            <button id="nextPage">下一页</button>
            <button id="lastPage">尾页</button>
        </div>
    </div>
<script>
class DataTable {
    constructor() {
        this.data = [];
        this.currentPage = 1;
        this.rowsPerPage = 10;
        this.sortColumn = null;
        this.sortDirection = 'asc';
        
        this.init();
    }

    init() {
        this.loadData();
        this.bindEvents();
    }

    async loadData() {
        try {
            const response = await fetch('?act=list&tt=tt');
            const jsonData = await response.json();
            this.data = jsonData;
            this.setupTable();
            this.renderTable();
            this.setupPagination();
        } catch (error) {
            console.error('数据加载失败:', error);
        }
    }

    setupTable() {
        if (this.data.length === 0) return;
        
        const headerRow = document.getElementById('headerRow');
        headerRow.innerHTML = '';
        
        // 创建表头
        Object.keys(this.data[0]).forEach(key => {
            const th = document.createElement('th');
            th.innerHTML = `
                ${key}
                <div class="sort-arrows">
                    <span class="arrow up" data-column="${key}">▲</span>
                    <span class="arrow down" data-column="${key}">▼</span>
                </div>
            `;
            headerRow.appendChild(th);
        });
    }

    renderTable() {
        const tableBody = document.getElementById('tableBody');
        tableBody.innerHTML = '';

        // 排序数据
        let sortedData = [...this.data];
        if (this.sortColumn) {
            sortedData.sort((a, b) => {
                const aVal = a[this.sortColumn];
                const bVal = b[this.sortColumn];
                if (this.sortDirection === 'asc') {
                    return aVal > bVal ? 1 : -1;
                } else {
                    return aVal < bVal ? 1 : -1;
                }
            });
        }

        // 分页
        const start = (this.currentPage - 1) * this.rowsPerPage;
        const paginatedData = sortedData.slice(start, start + this.rowsPerPage);

        // 渲染数据行
        paginatedData.forEach(row => {
            const tr = document.createElement('tr');
            Object.values(row).forEach(value => {
                const td = document.createElement('td');
                td.textContent = value;
                tr.appendChild(td);
            });
            tableBody.appendChild(tr);
        });
    }

    setupPagination() {
        const totalPages = Math.ceil(this.data.length / this.rowsPerPage);
        const pageSelect = document.getElementById('pageSelect');
        pageSelect.innerHTML = '';

        for (let i = 1; i <= totalPages; i++) {
            const option = document.createElement('option');
            option.value = i;
            option.textContent = `第${i}页`;
            pageSelect.appendChild(option);
        }
    }

    bindEvents() {
        // 排序事件
        document.getElementById('headerRow').addEventListener('click', (e) => {
            const arrow = e.target.closest('.arrow');
            if (!arrow) return;

            const column = arrow.dataset.column;
            const isUp = arrow.classList.contains('up');

            // 重置所有箭头样式
            document.querySelectorAll('.arrow').forEach(a => a.classList.remove('active'));
            
            // 设置当前箭头样式
            arrow.classList.add('active');

            this.sortColumn = column;
            this.sortDirection = isUp ? 'asc' : 'desc';
            this.renderTable();
        });

        // 分页事件
        document.getElementById('firstPage').addEventListener('click', () => {
            this.currentPage = 1;
            this.renderTable();
        });

        document.getElementById('prevPage').addEventListener('click', () => {
            if (this.currentPage > 1) {
                this.currentPage--;
                this.renderTable();
            }
        });

        document.getElementById('pageSelect').addEventListener('change', (e) => {
            this.currentPage = parseInt(e.target.value);
            this.renderTable();
        });

        document.getElementById('nextPage').addEventListener('click', () => {
            const totalPages = Math.ceil(this.data.length / this.rowsPerPage);
            if (this.currentPage < totalPages) {
                this.currentPage++;
                this.renderTable();
            }
        });

        document.getElementById('lastPage').addEventListener('click', () => {
            this.currentPage = Math.ceil(this.data.length / this.rowsPerPage);
            this.renderTable();
        });
    }
}

// 初始化表格
document.addEventListener('DOMContentLoaded', () => {
    new DataTable();
});
</script>
</body>
</html>

数据示范:制表符分隔的,可以直接excel复制粘贴

html 复制代码
姓名	学号	身份证号	科目1	科目2	科目3	科目4	科目5	科目.	科目N
李一	10001001	90001001	87	84	75	91	83	76	87
李二	10001002	90001002	95	81	81	71	60	82	99
李三	10001003	90001003	68	80	65	79	68	71	91
李四	10001004	90001004	82	80	75	90	87	64	81
李五	10001005	90001005	60	64	61	71	73	85	61
相关推荐
LuckyLay6 分钟前
Vue百日学习计划Day9-15天详细计划-Gemini版
前端·vue.js·学习
码农黛兮_463 小时前
4. 文字效果/2D-3D转换 - 3D翻转卡片
3d·html·css3
水银嘻嘻6 小时前
12 web 自动化之基于关键字+数据驱动-反射自动化框架搭建
运维·前端·自动化
小嘟嚷ovo7 小时前
h5,原生html,echarts关系网实现
前端·html·echarts
十一吖i7 小时前
Vue3项目使用ElDrawer后select方法不生效
前端
只可远观7 小时前
Flutter目录结构介绍、入口、Widget、Center组件、Text组件、MaterialApp组件、Scaffold组件
前端·flutter
周胡杰7 小时前
组件导航 (HMRouter)+flutter项目搭建-混合开发+分栏效果
前端·flutter·华为·harmonyos·鸿蒙·鸿蒙系统
敲代码的小吉米7 小时前
前端上传el-upload、原生input本地文件pdf格式(纯前端预览本地文件不走后端接口)
前端·javascript·pdf·状态模式
是千千千熠啊7 小时前
vue使用Fabric和pdfjs完成合同签章及批注
前端·vue.js
九月TTS8 小时前
TTS-Web-Vue系列:组件逻辑分离与模块化重构
前端·vue.js·重构