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

Vue自定义DataTable问题:数据更新刷新与操作按钮实现

解决Vue自定义DataTable的两个核心问题

一、增删数据后表格不更新的修复

问题根源

  1. 测试页面中tableRows未声明为响应式变量,数据更新后组件无法感知变化
  2. HTable组件仅在初始化时复制rows props的值,未监听后续props的更新,导致父组件数据变化后子组件不同步

修复步骤

  1. 测试页面中声明响应式的tableRows
    将普通数组改为ref响应式变量,确保数据变更能触发组件更新:

    // 替换原let tableRows = [];
    const tableRows = ref([]);
    

    同时在buildTableRows中,修改数据push方式为tableRows.value.push(row)。

  2. HTable组件监听rows props的变化
    在组件的setup中添加watch监听,同步父组件的rows更新并重置分页:

    watch(() => props.rows, (newRows) => {
        entries.value = [...newRows];
        currentPage.value = 1;
        paginateData(entries.value);
    }, { deep: true });
    

二、编辑/删除按钮点击不生效的修复

问题根源

调用buildLink时传递的是字符串形式的函数调用(如editItem(${id})),而Vue的@click需要绑定实际的函数引用,字符串无法被正确执行。

修复步骤

  1. 传递绑定参数的函数引用
    在测试页面的buildTableRows中,直接传递绑定了对应id的箭头函数,而非字符串:
    // 替换原字符串形式的clickFunction
    dataTable.buildLink(colThree, "Edit", "", () => editItem(tableData.value[i].id));
    dataTable.buildLink(colThree, "Delete", "", () => deleteItem(tableData.value[i].id));
    
  2. 组件中直接调用函数
    HTable组件中保留@click="link.click"即可,此时link.click是有效的函数引用。

修改后的核心代码片段

测试页面关键代码

<script>
    import { ref, onBeforeMount, watch } from "vue";
    import { dataTable } from '../shared';
    import HTable from '@/components/form-components/h-table';
    
    export default {
        components: {
            HTable,
        },
        setup() {
            let id = ref(3);
            const tableData = ref([
                { id: 1, name: "Mark", color: "Orange" },
                { id: 2, name: "David", color: "Red" },
                { id: 3, name: "Ashley", color: "Pink" },
            ]);

            const tableHeaders = [
                { label: "One" },
                { label: "Two" },
                { label: "Three" },
                { label: "" } //Links
            ];

            // 改为响应式变量
            const tableRows = ref([]);

            const buildTableRows = () => {
                tableRows.value = [];
                for (var i = 0; i < tableData.value.length; i++) {
                    var row = dataTable.buildRow();
                    dataTable.buildColumn(row, tableData.value[i].id);
                    dataTable.buildColumn(row, tableData.value[i].name);
                    dataTable.buildColumn(row, tableData.value[i].color);
                    var colThree = dataTable.buildColumn(row, "");
                    // 传递绑定id的函数
                    dataTable.buildLink(colThree, "Edit", "", () => editItem(tableData.value[i].id));
                    dataTable.buildLink(colThree, "Delete", "", () => deleteItem(tableData.value[i].id));

                    tableRows.value.push(row);
                }
            }

            const addNew = () => {
                id.value += 1;
                const newTest = {
                    id: id.value,
                    name: `Name-${id.value}`,
                    color: `Color-${id.value}`
                };
                tableData.value.push(newTest);
            }

            const editItem = (id) => {
                console.log("编辑:", id);
            };
            const deleteItem = (id) => {
                console.log("删除:", id);
                // 新增删除逻辑
                tableData.value = tableData.value.filter(item => item.id !== id);
            };

            watch(tableData, () => { buildTableRows(); }, { deep: true });

            onBeforeMount(() => {
                buildTableRows();
            });

            return { tableHeaders, tableRows, addNew, editItem, deleteItem }
        }
    }
</script>

HTable组件关键代码

<script>
    import { ref, computed, watch } from 'vue';
    import { dataTable } from '../../shared';
    export default {
        props: {
            id: String,
            headers: Array,
            rows: Array
        },
        setup(props) {
            let entries = ref([...props.rows]);
            let currentPage = ref(1);
            let searchInput = ref("");     
            let entriesToDisplay = ref(5);
            let filteredRows = ref(dataTable.paginate(entries.value, currentPage.value, entriesToDisplay.value));

            // 监听rows props变更
            watch(() => props.rows, (newRows) => {
                entries.value = [...newRows];
                currentPage.value = 1;
                paginateData(entries.value);
            }, { deep: true });

            let paginiation = () => {
                currentPage.value = 1;
                filteredRows.value = dataTable.paginate(entries.value, currentPage.value, entriesToDisplay.value);
            };

            let totalPages = computed(() => dataTable.pages(entries.value, entriesToDisplay.value))
            const viewInfo = computed(() => dataTable.pageInfo(entries.value, currentPage.value, entriesToDisplay.value));
            let pages = computed(() => dataTable.pagination(totalPages.value));

            const search = () => {
                currentPage.value = 1;
                entries.value = dataTable.search(props.rows, searchInput.value);
                paginateData(entries.value);
            }
            const paginateData = (data) => {
                filteredRows.value = dataTable.paginate(data, currentPage.value, entriesToDisplay.value);
            }
            const paginateEntries = (action, page) => {
                switch (action) {
                    case "previous":
                        currentPage.value = Math.max(1, currentPage.value - 1);
                        break;
                    case "next":
                        currentPage.value = Math.min(totalPages.value, currentPage.value + 1);
                        break;
                    case "page":
                        currentPage.value = page
                        break;
                }
                paginateData(entries.value);
            };

            return {
                entries,
                entriesToDisplay,
                currentPage,
                searchInput,
                filteredRows,
                paginiation,
                search,
                paginateData,
                paginateEntries,
                viewInfo,
                totalPages,
                pages
            }
        }
    }
</script>

额外优化建议

  • props类型校验:给HTable组件的props添加类型和必填校验,避免传入错误格式的数据
  • 分页逻辑简化:使用Math.max/Math.min替代冗余的三元判断,提升代码可读性
  • 搜索逻辑优化:可将搜索防抖处理,减少频繁触发搜索的性能消耗

内容的提问来源于stack exchange,提问作者Aaron Walker

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 13:20:29