主页/jQuery教程/综合实战项目/jQuery项目三:动态数据表格(Ajax加载、排序、过滤)

jQuery项目三:动态数据表格(Ajax加载、排序、过滤)

8,007字
34–51 分钟

概览

目录

动态数据表格是现代Web应用中展示和管理数据集的常见组件。本实战项目将综合运用 jQuery 的Ajax方法、DOM操作和事件处理,构建一个功能完备的表格系统。该表格能够通过Ajax从服务器加载JSON数据,支持点击表头进行升序/降序排序,并提供基于关键词的实时过滤功能。通过这个项目,可以深入理解如何利用 jQuery 简洁高效地处理异步数据、动态渲染UI以及实现交互逻辑。

项目准备

构建动态数据表格前,需要规划基础的HTML结构和CSS样式。表格由表头(<thead>)和表体(<tbody>)组成,表头中的可排序列应具备点击事件。同时需要一个输入框用于过滤数据。CSS负责呈现表格的视觉样式和排序指示符。

示例:基础HTML结构与样式
以下代码定义了表格容器、搜索框以及基础的CSS样式,为后续的JavaScript功能提供骨架。

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>jQuery 动态数据表格项目</title>
    <script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
    <style>
        body { font-family: Arial, sans-serif; margin: 20px; }
        #search { width: 100%; padding: 10px; margin-bottom: 20px; border: 1px solid #ccc; border-radius: 4px; }
        table { width: 100%; border-collapse: collapse; }
        th, td { padding: 10px; text-align: left; border-bottom: 1px solid #ddd; }
        th { background-color: #f2f2f2; cursor: pointer; user-select: none; }
        th.sort-asc::after { content: " ▲"; }
        th.sort-desc::after { content: " ▼"; }
        tr:hover { background-color: #f5f5f5; }
    </style>
</head>
<body>
    <h2>动态数据表格</h2>
    <input type="text" id="search" placeholder="输入关键词过滤...">
    <table id="data-table">
        <thead>
            <tr>
                <th data-sort="id">ID</th>
                <th data-sort="title">标题</th>
                <th data-sort="body">内容</th>
            </tr>
        </thead>
        <tbody>
            <!-- 动态数据将填充于此 -->
        </tbody>
    </table>

    <!-- JavaScript 代码将放在此处或单独文件 -->
</body>
</html>

Ajax加载数据

表格的数据源来自远程API。使用 jQuery$.ajax()$.getJSON() 方法可以方便地发起HTTP请求并处理返回的JSON数据。成功获取数据后,需要将其渲染为表格行并插入到 <tbody> 中。

语法

$.ajax({
    url: '数据接口地址',
    method: 'GET',
    dataType: 'json',
    success: function(data) {
        // 处理数据,渲染表格
    },
    error: function(xhr, status, error) {
        console.error('数据加载失败:', error);
    }
});

示例:Ajax加载数据并渲染表格

以下示例从公开API https://jsonplaceholder.typicode.com/posts 获取文章数据,并动态生成表格行。

<!-- 接上面的HTML结构,在 <body> 底部添加以下脚本 -->
<script>
$(document).ready(function() {
    const $tbody = $('#data-table tbody');
    let originalData = []; // 存储原始数据

    // 加载数据
    $.ajax({
        url: 'https://jsonplaceholder.typicode.com/posts',
        method: 'GET',
        dataType: 'json',
        success: function(data) {
            originalData = data;
            renderTable(data); // 初次渲染
        },
        error: function() {
            $tbody.html('<tr><td colspan="3">数据加载失败</td></tr>');
        }
    });

    // 渲染表格函数
    function renderTable(data) {
        const rows = data.map(item => `
            <tr>
                <td>${item.id}</td>
                <td>${item.title}</td>
                <td>${item.body}</td>
            </tr>
        `).join('');
        $tbody.html(rows);
    }
});
</script>

实现排序功能

排序功能允许点击表头时根据该列对数据进行重新排序。需要记录当前排序列和排序方向(升序/降序)。排序逻辑基于JavaScript的数组 sort 方法,对数据重新排序后调用 renderTable 更新视图。

示例:添加排序逻辑

在原有脚本基础上增加对表头点击的处理,并维护排序状态。

<script>
$(document).ready(function() {
    const $tbody = $('#data-table tbody');
    const $th = $('#data-table thead th');
    let originalData = [];
    let currentSort = { column: 'id', direction: 'asc' }; // 当前排序状态

    // 加载数据(同上)
    $.ajax({ /* ... */ });

    // 渲染表格函数(同上)
    function renderTable(data) { /* ... */ }

    // 排序函数
    function sortData(data, column, direction) {
        return data.sort((a, b) => {
            let valA = a[column];
            let valB = b[column];
            if (typeof valA === 'string') valA = valA.toLowerCase();
            if (typeof valB === 'string') valB = valB.toLowerCase();
            if (valA < valB) return direction === 'asc' ? -1 : 1;
            if (valA > valB) return direction === 'asc' ? 1 : -1;
            return 0;
        });
    }

    // 处理表头点击
    $th.on('click', function() {
        const column = $(this).data('sort'); // 获取排序字段
        const $this = $(this);
        // 更新排序方向
        if (currentSort.column === column) {
            currentSort.direction = currentSort.direction === 'asc' ? 'desc' : 'asc';
        } else {
            currentSort.column = column;
            currentSort.direction = 'asc';
        }
        // 更新表头样式
        $th.removeClass('sort-asc sort-desc');
        $this.addClass(currentSort.direction === 'asc' ? 'sort-asc' : 'sort-desc');

        // 对原始数据进行排序并重新渲染
        const sortedData = sortData([...originalData], column, currentSort.direction);
        renderTable(sortedData);
    });
});
</script>

实现过滤功能

过滤功能根据搜索框输入的关键词动态筛选数据,只显示包含该关键词的行。过滤逻辑基于原始数据,对每个字段进行模糊匹配,匹配结果重新渲染。为提升性能,可考虑防抖(debounce)处理。

示例:添加实时过滤

在脚本中增加对搜索框输入事件的监听,并实现过滤函数。

<script>
$(document).ready(function() {
    // ... 前面的代码保持不变 ...
    const $search = $('#search');

    // 过滤函数
    function filterData(data, keyword) {
        if (!keyword) return data;
        const lowerKeyword = keyword.toLowerCase();
        return data.filter(item => 
            item.title.toLowerCase().includes(lowerKeyword) ||
            item.body.toLowerCase().includes(lowerKeyword) ||
            item.id.toString().includes(lowerKeyword)
        );
    }

    // 处理搜索输入(使用防抖避免频繁渲染)
    let debounceTimer;
    $search.on('input', function() {
        clearTimeout(debounceTimer);
        const keyword = $(this).val();
        debounceTimer = setTimeout(() => {
            // 先排序(保持当前排序状态),再过滤
            let filtered = filterData(originalData, keyword);
            filtered = sortData(filtered, currentSort.column, currentSort.direction);
            renderTable(filtered);
        }, 300);
    });

    // 注意:初始数据加载后,应将原始数据存储在 originalData 中
});
</script>

完整项目示例

将以上所有部分整合,形成一个完整的动态数据表格页面。该页面从API加载文章数据,支持点击表头排序和输入框实时过滤。

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>jQuery 动态数据表格 - 完整示例</title>
    <script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
    <style>
        body { font-family: Arial, sans-serif; margin: 20px; }
        #search { width: 100%; padding: 10px; margin-bottom: 20px; border: 1px solid #ccc; border-radius: 4px; }
        table { width: 100%; border-collapse: collapse; }
        th, td { padding: 10px; text-align: left; border-bottom: 1px solid #ddd; }
        th { background-color: #f2f2f2; cursor: pointer; user-select: none; }
        th.sort-asc::after { content: " ▲"; }
        th.sort-desc::after { content: " ▼"; }
        tr:hover { background-color: #f5f5f5; }
    </style>
</head>
<body>
    <h2>动态数据表格 - 文章列表</h2>
    <input type="text" id="search" placeholder="输入关键词过滤...">
    <table id="data-table">
        <thead>
            <tr>
                <th data-sort="id">ID</th>
                <th data-sort="title">标题</th>
                <th data-sort="body">内容</th>
            </tr>
        </thead>
        <tbody>
            <!-- 动态数据将填充于此 -->
        </tbody>
    </table>

    <script>
    $(document).ready(function() {
        const $tbody = $('#data-table tbody');
        const $th = $('#data-table thead th');
        const $search = $('#search');
        let originalData = [];
        let currentSort = { column: 'id', direction: 'asc' };

        // 加载数据
        $.ajax({
            url: 'https://jsonplaceholder.typicode.com/posts',
            method: 'GET',
            dataType: 'json',
            success: function(data) {
                originalData = data;
                renderTable(data);
            },
            error: function() {
                $tbody.html('<tr><td colspan="3">数据加载失败</td></tr>');
            }
        });

        // 渲染表格
        function renderTable(data) {
            const rows = data.map(item => `
                <tr>
                    <td>${item.id}</td>
                    <td>${escapeHtml(item.title)}</td>
                    <td>${escapeHtml(item.body)}</td>
                </tr>
            `).join('');
            $tbody.html(rows);
        }

        // 简单的转义函数,防止XSS
        function escapeHtml(text) {
            return String(text).replace(/[&<>"]/g, function(m) {
                if (m === '&') return '&amp;';
                if (m === '<') return '&lt;';
                if (m === '>') return '&gt;';
                if (m === '"') return '&quot;';
                return m;
            });
        }

        // 排序
        function sortData(data, column, direction) {
            return data.sort((a, b) => {
                let valA = a[column];
                let valB = b[column];
                if (typeof valA === 'string') valA = valA.toLowerCase();
                if (typeof valB === 'string') valB = valB.toLowerCase();
                if (valA < valB) return direction === 'asc' ? -1 : 1;
                if (valA > valB) return direction === 'asc' ? 1 : -1;
                return 0;
            });
        }

        // 过滤
        function filterData(data, keyword) {
            if (!keyword) return data;
            const lowerKeyword = keyword.toLowerCase();
            return data.filter(item => 
                item.title.toLowerCase().includes(lowerKeyword) ||
                item.body.toLowerCase().includes(lowerKeyword) ||
                item.id.toString().includes(lowerKeyword)
            );
        }

        // 表头点击排序
        $th.on('click', function() {
            const column = $(this).data('sort');
            const $this = $(this);
            if (currentSort.column === column) {
                currentSort.direction = currentSort.direction === 'asc' ? 'desc' : 'asc';
            } else {
                currentSort.column = column;
                currentSort.direction = 'asc';
            }
            $th.removeClass('sort-asc sort-desc');
            $this.addClass(currentSort.direction === 'asc' ? 'sort-asc' : 'sort-desc');

            // 先过滤,再排序
            const filtered = filterData(originalData, $search.val());
            const sorted = sortData(filtered, column, currentSort.direction);
            renderTable(sorted);
        });

        // 搜索框输入过滤(防抖)
        let debounceTimer;
        $search.on('input', function() {
            clearTimeout(debounceTimer);
            const keyword = $(this).val();
            debounceTimer = setTimeout(() => {
                // 基于原始数据过滤,然后应用当前排序
                let filtered = filterData(originalData, keyword);
                filtered = sortData(filtered, currentSort.column, currentSort.direction);
                renderTable(filtered);
            }, 300);
        });
    });
    </script>
</body>
</html>

版本变更记录

下表梳理了 jQuery 版本迭代中与本项目相关的核心功能变更。

版本变更内容与影响
1.0提供基础的DOM操作和事件绑定方法,为动态表格的构建奠定基础。
1.5引入Deferred对象,$.ajax() 返回 jQuery Promise对象,使得异步流程控制更加灵活。
1.7统一事件API,使用 .on().off() 方法,简化了表头点击事件的管理。
3.0优化了 $.ajax 的性能和Promise兼容性,同时改进了对类数组对象的遍历。
4.0重大变更:在“slim”构建版本中移除了Deferred和Callbacks模块,但完整版本仍保留所有功能。若使用slim版本,本项目中基于Promise的Ajax流程需改用原生Promise或回调。此外,jQuery 4.0移除了一些已废弃API,但本示例中使用的核心方法不受影响。

浏览器兼容状态

本动态数据表格项目基于 jQuery 核心功能实现,其兼容性与 jQuery 库本身保持一致。下表列出了 jQuery 所支持的最低浏览器版本,在这些环境中,该项目能够正常工作。

浏览器最低支持版本
Chrome30+
Edge12+
Firefox25+
Opera18+
Safari7+
Chrome Android30+
Firefox for Android25+
Opera Android18+
Safari on iOS7+
Samsung Internet4.0+
WebView Android4.4+
WebView on iOS7+

:上述版本基于jQuery 3.x系列的兼容性测试。对于需要支持旧版浏览器(如IE 6-8)的项目,可以使用jQuery 1.x系列,但需注意部分API(如事件委托)的行为存在差异。本项目演示了如何利用 jQuery 简洁地构建交互式数据表格,通过Ajax、排序和过滤功能,展示了 jQuery 在现代Web开发中的实用价值。