Vue自定义DataTable问题:数据更新刷新与操作按钮实现
解决Vue自定义DataTable的两个核心问题
一、增删数据后表格不更新的修复
问题根源
- 测试页面中
tableRows未声明为响应式变量,数据更新后组件无法感知变化 - HTable组件仅在初始化时复制
rowsprops的值,未监听后续props的更新,导致父组件数据变化后子组件不同步
修复步骤
测试页面中声明响应式的tableRows
将普通数组改为ref响应式变量,确保数据变更能触发组件更新:// 替换原let tableRows = []; const tableRows = ref([]);同时在
buildTableRows中,修改数据push方式为tableRows.value.push(row)。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需要绑定实际的函数引用,字符串无法被正确执行。
修复步骤
- 传递绑定参数的函数引用
在测试页面的buildTableRows中,直接传递绑定了对应id的箭头函数,而非字符串:// 替换原字符串形式的clickFunction dataTable.buildLink(colThree, "Edit", "", () => editItem(tableData.value[i].id)); dataTable.buildLink(colThree, "Delete", "", () => deleteItem(tableData.value[i].id)); - 组件中直接调用函数
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
相关产品推荐
相关产品推荐

