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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 20:55:57