Vuetify3中v-data-table展开按钮绑定监听并保留展开功能
Vue3中v-data-table展开前预加载详情的实现方案
要实现点击展开按钮时先从服务器获取详情,同时保留原有展开功能,核心是自定义展开按钮的点击逻辑,配合Vuetify提供的expanded属性控制行的展开状态,具体实现如下:
1. 自定义展开列插槽
替换v-data-table默认的展开按钮插槽,绑定自定义点击事件,拦截原始展开行为,加入预加载逻辑。
2. 控制展开状态
通过expanded属性跟踪当前展开的行,配合@update:expanded事件同步状态,确保组件内部状态与自定义变量一致。
3. 实现预加载逻辑
在点击事件中先判断当前行是否已获取详情:
- 未获取时,先调用接口请求详情,请求完成后触发展开
- 已获取或需要收起时,直接修改展开状态数组即可
完整代码示例
<template> <v-data-table density="compact" :items="state.items" :expanded="expandedRows" @update:expanded="handleExpandedUpdate" > <!-- 自定义展开按钮,替换默认插槽 --> <template v-slot:item.data-table-expand="{ item }"> <v-btn icon @click="handleExpandClick(item)" :disabled="item?.details?.loading" > <v-icon> {{ expandedRows.includes(item) ? 'mdi-chevron-down' : 'mdi-chevron-right' }} </v-icon> </v-btn> </template> <!-- 展开行内容插槽 --> <template v-slot:expanded-row="{ columns, item }"> <tr> <td :colspan="columns.length"> <div v-if="item.details?.loading" class="pa-4 flex items-center gap-2"> <v-progress-circular size="24" indeterminate /> <span>加载详情中...</span> </div> <div v-else-if="item.details" class="pa-4"> <!-- 渲染获取到的详情内容 --> <h4>{{ item.name }} 详情</h4> <p>{{ item.details.description }}</p> <p>创建时间:{{ item.details.createTime }}</p> </div> <div v-else class="pa-4 text-red"> 加载失败,请重试 </div> </td> </tr> </template> </v-data-table> </template> <script setup> import { ref, reactive } from 'vue'; // 初始列表数据 const state = reactive({ items: [ { id: 1, name: '用户A' }, { id: 2, name: '用户B' }, { id: 3, name: '用户C' } ] }); // 跟踪展开的行 const expandedRows = ref([]); // 模拟接口请求:根据ID获取详情 const fetchItemDetails = async (itemId) => { // 替换为你的实际接口调用 await new Promise(resolve => setTimeout(resolve, 1200)); return { description: `这是ID为${itemId}的用户详细描述信息`, createTime: '2024-05-20 14:30:00' }; }; // 处理展开按钮点击事件 const handleExpandClick = async (item) => { const isExpanded = expandedRows.value.includes(item); // 已展开则直接收起 if (isExpanded) { expandedRows.value = expandedRows.value.filter(i => i.id !== item.id); return; } // 未展开时检查是否已有详情 if (!item.details) { // 标记加载状态 item.details = { loading: true }; try { // 请求详情 const details = await fetchItemDetails(item.id); item.details = details; // 请求成功后展开该行 expandedRows.value = [...expandedRows.value, item]; } catch (error) { // 请求失败,清除加载状态 item.details = null; console.error('获取详情失败:', error); } } else { // 已有详情,直接展开 expandedRows.value = [...expandedRows.value, item]; } }; // 同步组件内置的展开状态更新 const handleExpandedUpdate = (newExpanded) => { expandedRows.value = newExpanded; }; </script>
关键说明
- 插槽替换:通过
item.data-table-expand插槽自定义展开按钮,完全掌控点击逻辑,避免默认行为直接触发展开。 - 状态控制:使用
expanded属性绑定展开行数组,确保组件的展开状态与自定义变量同步,避免状态不一致。 - 加载反馈:添加加载中UI提示,同时禁用按钮防止重复点击,提升用户体验。
- 重复请求拦截:通过
item.details判断是否已获取详情,避免重复请求同一行数据。
内容的提问来源于stack exchange,提问作者eszik.k
相关产品推荐
相关产品推荐

