表格

QTable 组件可以以表格的形式展示数据,通常被称为数据表,包含以下主要功能:

  • 筛选
  • 排序
  • 对单行/多行数据进行自定义操作
  • 分页(包括服务端排序)
  • 网格模式(例如您可以使用 QCard 以非表格的形式展示数据)
  • 通过作用域槽对某行或某个单元格进行自定义
  • 能够在数据行的顶部或底部添加额外的行
  • 选择某列(通过 QTableColumns 组件)
  • 自定义表格顶部或底部的控件
  • 响应式设计

TIP

如果您不需要分页、排序、筛选等功能,可以考虑使用 QMarkupTable 组件代替。

QTable API

QTable API


fullscreen
: Boolean
说明
全屏模式
no-route-fullscreen-exit
: Boolean
说明
更改路由应用程序不会退出全屏模式
virtual-scroll-target
: Element | String
说明
用作自定义滚动容器的 CSS 选择器或 DOM 元素,而不是自动检测到的容器。
virtual-scroll-sticky-size-start
: Number | String
说明
使用的粘性标题的像素大小(如果使用);正确的值将提高滚动精度;在使用 scrollTo 方法时,也将用于非虚拟滚动表格以修复顶部对齐。
grid
: Boolean
说明
以网格形式显示数据,而不是默认的表格形式
grid-header
: Boolean
说明
在网格模式下也显示标题栏
loading
: Boolean
说明
将表格设置为“加载”状态;通知用户在幕后发生了一些事情

QTh API

QTh API


auto-width
: Boolean
说明
尝试缩小表头列的宽度大小;适用于带有复选框/单选按钮/切换按钮的列

QTr API

QTr API


props
: Object
说明
QTable 的行作用域插槽属性

QTd API

QTd API


auto-width
: Boolean
说明
尝试缩小列宽大小;适用于带有复选框/单选按钮/切换的列

定义数据

我们来看一个示例来学习配置 columns 属性。我们会告诉 QTable row-key 是 “name” 且必须唯一,如果数据来自于数据库,我们通常会使用 id 作为 row-key

columns: [ // 一个对象数组
  // column 对象定义
  {
    // 唯一的 id
    // 某列数据的标识
    // 会在 pagination.sortBy,"body-cell-[name],slot 等地方使用。
    name: 'desc',

    // 头部的标签
    label: 'Dessert (100g serving)',

    // 决定此列数据使用对象中的哪个字段
    field: 'name',
    // 或者 field: row => row.some.nested.prop,

    // (可选的)  如果我们使用 visible-columns 属性,那么这个列将始终可见
    required: true,

    // (可选的) 对齐方式
    align: 'left',

    // (可选的) 告诉 QTable,您想要这个列是可排序的。
    sortable: true,

    // (可选的) 自定义排序函数
    sort: (a, b, rowA, rowB) => parseInt(a, 10) - parseInt(b, 10),
    // 函数返回值:
    //   * 小于 0 表示 a 小于 b,排序时 a 在 b 前面。
    //   * 等于 0,则 a 和 b 的位置保持不变,对其他不同的元素进行排序。
    //   * 大于 0 表示 a 大于 b,排序时 a 在 b 后面。

    // (可选的) 重写 'column-sort-order' 属性;
    // 设置排序顺序:
    // 'ad' (ascending-descending)表示升序降序
    // 'da' (descending-ascending)表示降序排序
    sortOrder: 'ad', // 或者 'da'

    // (可选的) 您可以使用一个函数来格式化数据
    format: (val, row) => `${val}%`,
    // 另一个格式化示例:
    // format: val => val
    //   ? /* val 值为 true 则使用勾选状态的 Unicode 字符:☑ */ "\u2611"
    //   : /* 否则使用未选中状态的 Unicode 字符:☐ */ "\u2610",

    // body td:
    style: 'width: 500px',
    // 或者使用一个函数 --> style: row => ... (return String/Array/Object)
    classes: 'my-special-class',
    // 或者使用一个函数 --> classes: row => ... (return String)

    // header th:
    headerStyle: 'width: 500px',
    headerClasses: 'my-special-class'
  },
  { name: 'calories', label: 'Calories', field: 'calories', sortable: true },
  { name: 'fat', label: 'Fat (g)', field: 'fat', sortable: true },
  { name: 'carbs', label: 'Carbs (g)', field: 'carbs' },
  { name: 'protein', label: 'Protein (g)', field: 'protein' },
  { name: 'sodium', label: 'Sodium (mg)', field: 'sodium' },
  { name: 'calcium', label: 'Calcium (%)', field: 'calcium', sortable: true, sort: (a, b) => parseInt(a, 10) - parseInt(b, 10) },
  { name: 'iron', label: 'Iron (%)', field: 'iron', sortable: true, sort: (a, b) => parseInt(a, 10) - parseInt(b, 10) }
]

基础用法



<template>
  <div class="q-pa-md">
    <q-table
      title="Treats"
      :rows="rows"
      :columns="columns"
      row-key="name"
    />
  </div>
</template>

Treats
Dessert (100g serving)CaloriesFat (g)Carbs (g)Protein (g)Sodium (mg)Calcium (%)Iron (%)
Frozen Yogurt15962448714%1%
Ice cream sandwich2379374.31298%1%
Eclair262162363376%7%
Cupcake3053.7674.34133%8%
Gingerbread35616493.93277%16%
每页的行数:
1-5 / 10


<template>
  <div class="q-pa-md">
    <q-table
      title="Treats"
      :rows="rows"
      :columns="columns"
      row-key="name"
      dark
      color="amber"
    />
  </div>
</template>

Treats
Dessert (100g serving)CaloriesFat (g)Carbs (g)Protein (g)Sodium (mg)Calcium (%)Iron (%)
Frozen Yogurt15962448714%1%
Ice cream sandwich2379374.31298%1%
Eclair262162363376%7%
Cupcake3053.7674.34133%8%
Gingerbread35616493.93277%16%
每页的行数:
1-5 / 10


<template>
  <div class="q-pa-md">
    <q-table
      title="Treats"
      dense
      :rows="rows"
      :columns="columns"
      row-key="name"
    />
  </div>
</template>

Treats
Dessert (100g serving)CaloriesFat (g)Carbs (g)Protein (g)Sodium (mg)Calcium (%)Iron (%)
Frozen Yogurt15962448714%1%
Ice cream sandwich2379374.31298%1%
Eclair262162363376%7%
Cupcake3053.7674.34133%8%
Gingerbread35616493.93277%16%
每页的行数:
1-5 / 10

TIP

您可以将 dense 属性与 $q.screen 搭配使用来实现响应式的效果。例如::dense="$q.screen.lt.md",更多信息请参考:Screen Plugin

省略列定义

您可以省略定义列 columns,QTable 会根据数据中的第一列进行推断。需要注意的是,标题会自动转为大写,并且排序会自动开启。



<template>
  <div class="q-pa-md">
    <q-table
      :rows="rows"
      row-key="name"
    />
  </div>
</template>

NAMECALORIESFATCARBSPROTEINSODIUMCALCIUMIRON
Frozen Yogurt15962448714%1%
Ice cream sandwich2379374.31298%1%
Eclair262162363376%7%
Cupcake3053.7674.34133%8%
Gingerbread35616493.93277%16%
每页的行数:
1-5 / 10

固定表头/列

WARNING

请注意,固定表头或行是通过 CSS 中的 position: sticky 属性实现的,并不是所有的浏览器都支持它。使用前,请检查 caniuse.com

TIP

固定表头或列都是由 css 实现的,所以在下面的几个示例中要注意 style 部分的代码,尤其是 position: sticky



<template>
  <div class="q-pa-md">
    <q-table
      class="my-sticky-header-table"
      title="Treats"
      :rows="rows"
      :columns="columns"
      row-key="name"
      flat
      bordered
    />
  </div>
</template>

Treats
Dessert (100g serving)CaloriesFat (g)Carbs (g)Protein (g)Sodium (mg)Calcium (%)Iron (%)
Frozen Yogurt15962448714%1%
Ice cream sandwich2379374.31298%1%
Eclair262162363376%7%
Cupcake3053.7674.34133%8%
Gingerbread35616493.93277%16%
每页的行数:
1-5 / 10


<template>
  <div class="q-pa-md">
    <q-table
      class="my-sticky-column-table"
      title="Treats"
      :rows="rows"
      :columns="columns"
      row-key="name"
    />
  </div>
</template>

Treats
Dessert (100g serving)CaloriesFat (g)Carbs (g)Protein (g)Sodium (mg)Calcium (%)Iron (%)
Frozen Yogurt15962448714%1%
Ice cream sandwich2379374.31298%1%
Eclair262162363376%7%
Cupcake3053.7674.34133%8%
Gingerbread35616493.93277%16%
每页的行数:
1-5 / 10


<template>
  <div class="q-pa-md">
    <q-table
      class="my-sticky-last-column-table"
      flat bordered
      title="Treats"
      :rows="rows"
      :columns="columns"
      row-key="name"
    />
  </div>
</template>

Treats
Dessert (100g serving)CaloriesFat (g)Carbs (g)Protein (g)Sodium (mg)Calcium (%)Iron (%)
Frozen Yogurt15962448714%1%
Ice cream sandwich2379374.31298%1%
Eclair262162363376%7%
Cupcake3053.7674.34133%8%
Gingerbread35616493.93277%16%
每页的行数:
1-5 / 10


<template>
  <div class="q-pa-md">
    <q-table
      class="my-sticky-header-column-table"
      title="Treats"
      :rows="rows"
      :columns="columns"
      row-key="name"
    />
  </div>
</template>

Treats
Dessert (100g serving)CaloriesFat (g)Carbs (g)Protein (g)Sodium (mg)Calcium (%)Iron (%)
Frozen Yogurt15962448714%1%
Ice cream sandwich2379374.31298%1%
Eclair262162363376%7%
Cupcake3053.7674.34133%8%
Gingerbread35616493.93277%16%
每页的行数:
1-5 / 10


<template>
  <div class="q-pa-md">
    <q-table
      class="my-sticky-header-last-column-table"
      flat bordered
      title="Treats"
      :rows="rows"
      :columns="columns"
      row-key="name"
    />
  </div>
</template>

Treats
Dessert (100g serving)CaloriesFat (g)Carbs (g)Protein (g)Sodium (mg)Calcium (%)Iron (%)
Frozen Yogurt15962448714%1%
Ice cream sandwich2379374.31298%1%
Eclair262162363376%7%
Cupcake3053.7674.34133%8%
Gingerbread35616493.93277%16%
每页的行数:
1-5 / 10

分割线



<template>
  <div class="q-pa-md">
    <q-option-group
      v-model="separator"
      inline
      class="q-mb-md"
      :options="[
        { label: 'Horizontal (default)', value: 'horizontal' },
        { label: 'Vertical', value: 'vertical' },
        { label: 'Cell', value: 'cell' },
        { label: 'None', value: 'none' },
      ]"
    />

    <q-table
      title="Treats"
      :rows="rows"
      :columns="columns"
      row-key="name"
      :separator="separator"
    />
  </div>
</template>

Treats
Dessert (100g serving)CaloriesFat (g)Carbs (g)Protein (g)Sodium (mg)Calcium (%)Iron (%)
Frozen Yogurt15962448714%1%
Ice cream sandwich2379374.31298%1%
Eclair262162363376%7%
Cupcake3053.7674.34133%8%
Gingerbread35616493.93277%16%
每页的行数:
1-5 / 10

样式



<template>
  <div class="q-pa-md">
    <q-table
      :rows="rows"
      :columns="columns"
      row-key="name"
    />
  </div>
</template>

Dessert (100g serving)CaloriesFat (g)Carbs (g)Protein (g)Sodium (mg)Calcium (%)Iron (%)
Frozen Yogurt15962448714%1%
Ice cream sandwich2379374.31298%1%
Eclair262162363376%7%
Cupcake3053.7674.34133%8%
Gingerbread35616493.93277%16%
每页的行数:
1-5 / 10


<template>
  <div class="q-pa-md">
    <q-table
      color="primary"
      card-class="bg-amber-5 text-brown"
      table-class="text-grey-8"
      table-header-class="text-brown"
      flat
      bordered
      title="Treats"
      :rows="rows"
      :columns="columns"
      row-key="name"
    />
  </div>
</template>

Treats
Dessert (100g serving)CaloriesFat (g)Carbs (g)Protein (g)Sodium (mg)Calcium (%)Iron (%)
Frozen Yogurt15962448714%1%
Ice cream sandwich2379374.31298%1%
Eclair262162363376%7%
Cupcake3053.7674.34133%8%
Gingerbread35616493.93277%16%
每页的行数:
1-5 / 10


<template>
  <div class="q-pa-md">
    <q-table
      title="Treats"
      :rows="rows"
      :columns="columns"
      row-key="name"
      hide-header
      hide-bottom
    />
  </div>
</template>

Treats
Frozen Yogurt15962448714%1%
Ice cream sandwich2379374.31298%1%
Eclair262162363376%7%
Cupcake3053.7674.34133%8%
Gingerbread35616493.93277%16%

虚拟滚动

当使用虚拟滚动时,您需要使用 table-style 属性声明一个最大高度。在下面的示例中,我们还强制一次性显示了所有的列(注意 paginationrows-per-page-options)。



<template>
  <div class="q-pa-md">
    <q-table
      style="height: 400px"
      title="Treats"
      :rows="rows"
      :columns="columns"
      row-key="index"
      virtual-scroll
      v-model:pagination="pagination"
      :rows-per-page-options="[0]"
    />
  </div>
</template>

Treats
#Dessert (100g serving)CaloriesFat (g)Carbs (g)Protein (g)Sodium (mg)Calcium (%)Iron (%)
0Frozen Yogurt15962448714%1%
1Ice cream sandwich2379374.31298%1%
2Eclair262162363376%7%
3Cupcake3053.7674.34133%8%
4Gingerbread35616493.93277%16%
5Jelly bean3750940500%0%
6Lollipop3920.2980380%2%
7Honeycomb4083.2876.55620%45%
8Donut45225514.93262%22%
9KitKat518266575412%6%
10Frozen Yogurt15962448714%1%
11Ice cream sandwich2379374.31298%1%
12Eclair262162363376%7%
13Cupcake3053.7674.34133%8%
14Gingerbread35616493.93277%16%
15Jelly bean3750940500%0%
16Lollipop3920.2980380%2%
17Honeycomb4083.2876.55620%45%
18Donut45225514.93262%22%
19KitKat518266575412%6%
20Frozen Yogurt15962448714%1%
1-10000 / 10000

您可以在滚动到底部时动态加载新数据:



<template>
  <div class="q-pa-md">
    <q-table
      class="my-sticky-dynamic"
      title="Treats"
      :rows="rows"
      :columns="columns"
      :loading="loading"
      row-key="index"
      virtual-scroll
      :virtual-scroll-item-size="48"
      :virtual-scroll-sticky-size-start="48"
      :pagination="pagination"
      :rows-per-page-options="[0]"
      @virtual-scroll="onScroll"
    />
  </div>
</template>

Treats
#Dessert (100g serving)CaloriesFat (g)Carbs (g)Protein (g)Sodium (mg)Calcium (%)Iron (%)
0Frozen Yogurt15962448714%1%
1Ice cream sandwich2379374.31298%1%
2Eclair262162363376%7%
3Cupcake3053.7674.34133%8%
4Gingerbread35616493.93277%16%
5Jelly bean3750940500%0%
6Lollipop3920.2980380%2%
7Honeycomb4083.2876.55620%45%
8Donut45225514.93262%22%
9KitKat518266575412%6%
10Frozen Yogurt15962448714%1%
11Ice cream sandwich2379374.31298%1%
12Eclair262162363376%7%
13Cupcake3053.7674.34133%8%
14Gingerbread35616493.93277%16%
15Jelly bean3750940500%0%
16Lollipop3920.2980380%2%
17Honeycomb4083.2876.55620%45%
1-50 / 50

您可以同时使用虚拟滚动和分页:



<template>
  <div class="q-pa-md">
    <q-table
      style="height: 400px"
      title="Treats"
      :rows="rows"
      :columns="columns"
      row-key="index"
      virtual-scroll
      v-model:pagination="pagination"
      :rows-per-page-options="[0]"
    />
  </div>
</template>

Treats
#Dessert (100g serving)CaloriesFat (g)Carbs (g)Protein (g)Sodium (mg)Calcium (%)Iron (%)
0Frozen Yogurt15962448714%1%
1Ice cream sandwich2379374.31298%1%
2Eclair262162363376%7%
3Cupcake3053.7674.34133%8%
4Gingerbread35616493.93277%16%
5Jelly bean3750940500%0%
6Lollipop3920.2980380%2%
7Honeycomb4083.2876.55620%45%
8Donut45225514.93262%22%
9KitKat518266575412%6%
10Frozen Yogurt15962448714%1%
11Ice cream sandwich2379374.31298%1%
12Eclair262162363376%7%
13Cupcake3053.7674.34133%8%
14Gingerbread35616493.93277%16%
15Jelly bean3750940500%0%
16Lollipop3920.2980380%2%
17Honeycomb4083.2876.55620%45%
18Donut45225514.93262%22%
19KitKat518266575412%6%
20Frozen Yogurt15962448714%1%
1-1000 / 10000

下面的示例展示了如何将虚拟滚动与固定表头同时使用,请注意其中 virtual-scroll-sticky-start 属性被设置为了表头的高度。



<template>
  <div class="q-pa-md">
    <q-table
      class="my-sticky-virtscroll-table"
      virtual-scroll
      v-model:pagination="pagination"
      :rows-per-page-options="[0]"
      :virtual-scroll-sticky-size-start="48"
      row-key="index"
      title="Treats"
      :rows="rows"
      :columns="columns"
    />
  </div>
</template>

Treats
#Dessert (100g serving)CaloriesFat (g)Carbs (g)Protein (g)Sodium (mg)Calcium (%)Iron (%)
1-10000 / 10000

这里有两个工具 CSS 类名可以控制虚滚动的大小计算:

  • 使用 q-virtual-scroll--with-prev 类可以使被虚拟滚动渲染的元素与上一个元素一起分组(主要用于从同一行数据生成的多个表行)。
  • 使用 q-virtual-scroll--skip 类可以使被虚拟滚动渲染的元素在计算大小时忽略此元素的大小。


<template>
  <div class="q-pa-md">
    <q-table
      style="height: 400px"
      ref="tableRef"
      title="Treats"
      :rows="rows"
      :columns="columns"
      :table-colspan="9"
      row-key="index"
      virtual-scroll
      :virtual-scroll-item-size="48"
      :pagination="pagination"
      :rows-per-page-options="[0]"
    >

      <template v-slot:header="props">
        <q-tr :props="props">
          <q-th />

          <q-th
            v-for="col in props.cols"
            :key="col.name"
            :props="props"
          >
            {{ col.label }}
          </q-th>
        </q-tr>
      </template>

      <template v-slot:body="props">
        <q-tr :props="props" :key="`m_${props.row.index}`">
          <q-td>
            Index: {{ props.row.index }}
          </q-td>

          <q-td
            v-for="col in props.cols"
            :key="col.name"
            :props="props"
          >
            {{ col.value }}
          </q-td>
        </q-tr>
        <q-tr :props="props" :key="`e_${props.row.index}`" class="q-virtual-scroll--with-prev">
          <q-td colspan="100%">
            <div class="text-left">This is the second row generated from the same data: {{ props.row.name }} (Index: {{ props.row.index }}).</div>
          </q-td>
        </q-tr>
      </template>

    </q-table>
  </div>
</template>

Treats
Dessert (100g serving)CaloriesFat (g)Carbs (g)Protein (g)Sodium (mg)Calcium (%)Iron (%)
Index: 4994Cupcake3053.7674.34133%8%
This is the second row generated from the same data: Cupcake (Index: 4994).
Index: 4995Gingerbread35616493.93277%16%
This is the second row generated from the same data: Gingerbread (Index: 4995).
Index: 4996Jelly bean3750940500%0%
This is the second row generated from the same data: Jelly bean (Index: 4996).
Index: 4997Lollipop3920.2980380%2%
This is the second row generated from the same data: Lollipop (Index: 4997).
Index: 4998Honeycomb4083.2876.55620%45%
This is the second row generated from the same data: Honeycomb (Index: 4998).
Index: 4999Donut45225514.93262%22%
This is the second row generated from the same data: Donut (Index: 4999).
Index: 5000KitKat518266575412%6%
This is the second row generated from the same data: KitKat (Index: 5000).
Index: 5001Frozen Yogurt15962448714%1%
This is the second row generated from the same data: Frozen Yogurt (Index: 5001).
Index: 5002Ice cream sandwich2379374.31298%1%
This is the second row generated from the same data: Ice cream sandwich (Index: 5002).
Index: 5003Eclair262162363376%7%
This is the second row generated from the same data: Eclair (Index: 5003).
Index: 5004Cupcake3053.7674.34133%8%
This is the second row generated from the same data: Cupcake (Index: 5004).
Index: 5005Gingerbread35616493.93277%16%
This is the second row generated from the same data: Gingerbread (Index: 5005).
Index: 5006Jelly bean3750940500%0%
This is the second row generated from the same data: Jelly bean (Index: 5006).
Index: 5007Lollipop3920.2980380%2%
This is the second row generated from the same data: Lollipop (Index: 5007).
Index: 5008Honeycomb4083.2876.55620%45%
This is the second row generated from the same data: Honeycomb (Index: 5008).
Index: 5009Donut45225514.93262%22%
This is the second row generated from the same data: Donut (Index: 5009).
Index: 5010KitKat518266575412%6%
This is the second row generated from the same data: KitKat (Index: 5010).
Index: 5011Frozen Yogurt15962448714%1%
This is the second row generated from the same data: Frozen Yogurt (Index: 5011).
Index: 5012Ice cream sandwich2379374.31298%1%
This is the second row generated from the same data: Ice cream sandwich (Index: 5012).
Index: 5013Eclair262162363376%7%
This is the second row generated from the same data: Eclair (Index: 5013).
Index: 5014Cupcake3053.7674.34133%8%
This is the second row generated from the same data: Cupcake (Index: 5014).
1-10000 / 10000

选择

警告

为了使选中功能生效,必须设置 row-key 属性。



<template>
  <div class="q-pa-md">
    <q-table
      title="Treats"
      :rows="rows"
      :columns="columns"
      row-key="name"
      selection="single"
      v-model:selected="selected"
    />

    <div class="q-mt-md">
      Selected: {{ JSON.stringify(selected) }}
    </div>
  </div>
</template>

Treats
Dessert (100g serving)CaloriesFat (g)Carbs (g)Protein (g)Sodium (mg)Calcium (%)Iron (%)
Frozen Yogurt15962448714%1%
Ice cream sandwich2379374.31298%1%
Eclair262162363376%7%
Cupcake3053.7674.34133%8%
Gingerbread35616493.93277%16%
每页的行数:
1-5 / 10
Selected: []


<template>
  <div class="q-pa-md">
    <q-table
      title="Treats"
      :rows="rows"
      :columns="columns"
      row-key="name"
      :selected-rows-label="getSelectedString"
      selection="multiple"
      v-model:selected="selected"
    />

    <div class="q-mt-md">
      Selected: {{ JSON.stringify(selected) }}
    </div>
  </div>
</template>

Treats
Dessert (100g serving)CaloriesFat (g)Carbs (g)Protein (g)Sodium (mg)Calcium (%)Iron (%)
Frozen Yogurt15962448714%1%
Ice cream sandwich2379374.31298%1%
Eclair262162363376%7%
Cupcake3053.7674.34133%8%
Gingerbread35616493.93277%16%
每页的行数:
1-5 / 10
Selected: []


<template>
  <div class="q-pa-md">
    <q-table
      title="Treats"
      :rows="rows"
      :columns="columns"
      row-key="name"
      selection="multiple"
      v-model:selected="selected"
    >
      <template v-slot:header-selection="scope">
        <q-toggle v-model="scope.selected" />
      </template>

      <template v-slot:body-selection="scope">
        <q-toggle v-model="scope.selected" />
      </template>
    </q-table>
  </div>
</template>

Treats
Dessert (100g serving)CaloriesFat (g)Carbs (g)Protein (g)Sodium (mg)Calcium (%)Iron (%)
Frozen Yogurt15962448714%1%
Ice cream sandwich2379374.31298%1%
Eclair262162363376%7%
Cupcake3053.7674.34133%8%
Gingerbread35616493.93277%16%
每页的行数:
1-5 / 10


<template>
  <div class="q-pa-md">
    <q-table
      ref="tableRef"
      title="Treats"
      :rows="rows"
      :columns="columns"
      row-key="name"
      :selected-rows-label="getSelectedString"
      selection="multiple"
      :selected="selected"
      @selection="onSelection"
    />

    <div class="q-mt-md">
      Selected: {{ JSON.stringify(selected) }}
    </div>
  </div>
</template>

Treats
Dessert (100g serving)CaloriesFat (g)Carbs (g)Protein (g)Sodium (mg)Calcium (%)Iron (%)
Frozen Yogurt15962448714%1%
Ice cream sandwich2379374.31298%1%
Eclair262162363376%7%
Cupcake3053.7674.34133%8%
Gingerbread35616493.93277%16%
每页的行数:
1-5 / 10
Selected: []

隐藏列,自定义头部,全屏

请注意在列定义中被标记了 required 的列无法被隐藏,始终可见。



<template>
  <div class="q-pa-md">
    <q-table
      title="Treats"
      :rows="rows"
      :columns="columns"
      row-key="name"
      :visible-columns="visibleColumns"
    >
      <template v-slot:top="props">
        <div class="col-2 q-table__title">Treats</div>

        <q-space />

        <div v-if="$q.screen.gt.xs" class="col">
          <q-toggle v-model="visibleColumns" val="calories" label="Calories" />
          <q-toggle v-model="visibleColumns" val="fat" label="Fat" />
          <q-toggle v-model="visibleColumns" val="carbs" label="Carbs" />
          <q-toggle v-model="visibleColumns" val="protein" label="Protein" />
          <q-toggle v-model="visibleColumns" val="sodium" label="Sodium" />
          <q-toggle v-model="visibleColumns" val="calcium" label="Calcium" />
          <q-toggle v-model="visibleColumns" val="iron" label="Iron" />
        </div>
        <q-select
          v-else
          v-model="visibleColumns"
          multiple
          borderless
          dense
          options-dense
          :display-value="$q.lang.table.columns"
          emit-value
          map-options
          :options="columns"
          option-value="name"
          style="min-width: 150px"
        />

        <q-btn
          flat round dense
          :icon="props.inFullscreen ? 'fullscreen_exit' : 'fullscreen'"
          @click="props.toggleFullscreen"
          class="q-ml-md"
        />
      </template>

    </q-table>
  </div>
</template>

Treats
Calories
Fat
Carbs
Protein
Sodium
Calcium
Iron
Dessert (100g serving)CaloriesFat (g)Carbs (g)Protein (g)Sodium (mg)Calcium (%)Iron (%)
Frozen Yogurt15962448714%1%
Ice cream sandwich2379374.31298%1%
Eclair262162363376%7%
Cupcake3053.7674.34133%8%
Gingerbread35616493.93277%16%
每页的行数:
1-5 / 10


<template>
  <div class="q-pa-md">
    <q-table
      title="Treats"
      :rows="rows"
      :columns="columns"
      row-key="name"
      :visible-columns="visibleColumns"
    >
      <template v-slot:top>
        <img
          style="height: 50px; width: 50px"
          src="https://cdn.quasar.dev/logo-v2/svg/logo.svg"
        >

        <q-space />

        <q-select
          v-model="visibleColumns"
          multiple
          outlined
          dense
          options-dense
          :display-value="$q.lang.table.columns"
          emit-value
          map-options
          :options="columns"
          option-value="name"
          options-cover
          style="min-width: 150px"
        />
      </template>

    </q-table>
  </div>
</template>

Dessert (100g serving)CaloriesFat (g)Carbs (g)Protein (g)Sodium (mg)Calcium (%)Iron (%)
Frozen Yogurt15962448714%1%
Ice cream sandwich2379374.31298%1%
Eclair262162363376%7%
Cupcake3053.7674.34133%8%
Gingerbread35616493.93277%16%
每页的行数:
1-5 / 10

弹出编辑

TIP

下面的示例中,我们利用 QPopupEdit 组件实现了就地编辑数据的功能。请注意,我们使用的是 body 类型的插槽,如果使用单元格类型的插槽,QPopupEdit 无法生效。



<template>
  <div class="q-pa-md">
    <q-table
      title="Treats"
      :rows="rows"
      :columns="columns"
      row-key="name"
      binary-state-sort
    >
      <template v-slot:body="props">
        <q-tr :props="props">
          <q-td key="name" :props="props">
            {{ props.row.name }}
            <q-popup-edit v-model="props.row.name" v-slot="scope">
              <q-input v-model="scope.value" dense autofocus counter />
            </q-popup-edit>
          </q-td>
          <q-td key="calories" :props="props">
            {{ props.row.calories }}
            <q-popup-edit v-model="props.row.calories" title="Update calories" buttons v-slot="scope">
              <q-input type="number" v-model="scope.value" dense autofocus />
            </q-popup-edit>
          </q-td>
          <q-td key="fat" :props="props">
            <div class="text-pre-wrap">{{ props.row.fat }}</div>
            <q-popup-edit v-model="props.row.fat" v-slot="scope">
              <q-input type="textarea" v-model="scope.value" dense autofocus />
            </q-popup-edit>
          </q-td>
          <q-td key="carbs" :props="props">
            {{ props.row.carbs }}
            <q-popup-edit v-model="props.row.carbs" title="Update carbs" buttons persistent v-slot="scope">
              <q-input type="number" v-model="scope.value" dense autofocus hint="Use buttons to close" />
            </q-popup-edit>
          </q-td>
          <q-td key="protein" :props="props">{{ props.row.protein }}</q-td>
          <q-td key="sodium" :props="props">{{ props.row.sodium }}</q-td>
          <q-td key="calcium" :props="props">{{ props.row.calcium }}</q-td>
          <q-td key="iron" :props="props">{{ props.row.iron }}</q-td>
        </q-tr>
      </template>
    </q-table>
  </div>
</template>

Treats
Dessert (100g serving)CaloriesFat (g)Carbs (g)Protein (g)Sodium (mg)Calcium (%)Iron (%)
Frozen Yogurt 159
6
24 48714%1%
Ice cream sandwich 237
9
37 4.31298%1%
Eclair 262
16
23 63376%7%
Cupcake 305
3.7
67 4.34133%8%
Gingerbread 356
16
49 3.93277%16%
每页的行数:
1-5 / 10

网格样式

TIP

您可以将 grid 属性与 $q.screen 搭配使用以实现响应式的效果。例如::grid="$q.screen.lt.md". 更多信息请参考: 屏幕插件

下面的示例中,我们让 QTable 以网格模式展示(不使用特殊的插槽):



<template>
  <div class="q-pa-md">
    <q-table
      grid
      title="Treats"
      :rows="rows"
      :columns="columns"
      row-key="name"
      :filter="filter"
      hide-header
    >
      <template v-slot:top-right>
        <q-input borderless dense debounce="300" v-model="filter" placeholder="Search">
          <template v-slot:append>
            <q-icon name="search" />
          </template>
        </q-input>
      </template>
    </q-table>
  </div>
</template>

Treats
Dessert (100g serving)
Frozen Yogurt
Calories
159
Fat (g)
6
Carbs (g)
24
Dessert (100g serving)
Ice cream sandwich
Calories
237
Fat (g)
9
Carbs (g)
37
Dessert (100g serving)
Eclair
Calories
262
Fat (g)
16
Carbs (g)
23
Dessert (100g serving)
Cupcake
Calories
305
Fat (g)
3.7
Carbs (g)
67
Dessert (100g serving)
Gingerbread
Calories
356
Fat (g)
16
Carbs (g)
49
每页的行数:
1-5 / 10


<template>
  <div class="q-pa-md">
    <q-table
      grid
      grid-header
      title="Treats"
      :rows="rows"
      :columns="columns"
      row-key="name"
      :filter="filter"
      hide-header
    >
      <template v-slot:top-right>
        <q-input borderless dense debounce="300" v-model="filter" placeholder="Search">
          <template v-slot:append>
            <q-icon name="search" />
          </template>
        </q-input>
      </template>
    </q-table>
  </div>
</template>

Treats
Dessert (100g serving)CaloriesFat (g)Carbs (g)
Dessert (100g serving)
Frozen Yogurt
Calories
159
Fat (g)
6
Carbs (g)
24
Dessert (100g serving)
Ice cream sandwich
Calories
237
Fat (g)
9
Carbs (g)
37
Dessert (100g serving)
Eclair
Calories
262
Fat (g)
16
Carbs (g)
23
Dessert (100g serving)
Cupcake
Calories
305
Fat (g)
3.7
Carbs (g)
67
Dessert (100g serving)
Gingerbread
Calories
356
Fat (g)
16
Carbs (g)
49
每页的行数:
1-5 / 10


<template>
  <div class="q-pa-md">
    <q-table
      grid
      card-class="bg-primary text-white"
      title="Treats"
      :rows="rows"
      :columns="columns"
      row-key="name"
      :filter="filter"
      hide-header
    >
      <template v-slot:top-right>
        <q-input borderless dense debounce="300" v-model="filter" placeholder="Search">
          <template v-slot:append>
            <q-icon name="search" />
          </template>
        </q-input>
      </template>
    </q-table>
  </div>
</template>

Treats
Dessert (100g serving)
Frozen Yogurt
Calories
159
Fat (g)
6
Carbs (g)
24
Dessert (100g serving)
Ice cream sandwich
Calories
237
Fat (g)
9
Carbs (g)
37
Dessert (100g serving)
Eclair
Calories
262
Fat (g)
16
Carbs (g)
23
Dessert (100g serving)
Cupcake
Calories
305
Fat (g)
3.7
Carbs (g)
67
Dessert (100g serving)
Gingerbread
Calories
356
Fat (g)
16
Carbs (g)
49
每页的行数:
1-5 / 10


<template>
  <div class="q-pa-md">
    <q-table
      grid
      :card-container-class="cardContainerClass"
      title="Treats"
      :rows="rows"
      :columns="columns"
      row-key="name"
      :filter="filter"
      hide-header
      v-model:pagination="pagination"
      :rows-per-page-options="rowsPerPageOptions"
    >
      <template v-slot:top-right>
        <q-input borderless dense debounce="300" v-model="filter" placeholder="Search">
          <template v-slot:append>
            <q-icon name="search" />
          </template>
        </q-input>
      </template>

      <template v-slot:item="props">
        <div class="q-pa-xs col-xs-12 col-sm-6 col-md-4">
          <q-card>
            <q-card-section class="text-center">
              Calories for
              <br>
              <strong>{{ props.row.name }}</strong>
            </q-card-section>
            <q-separator />
            <q-card-section class="flex flex-center" :style="{ fontSize: props.row.calories + 'px' }">
              <div>{{ props.row.calories }} g</div>
            </q-card-section>
          </q-card>
        </div>
      </template>
    </q-table>
  </div>
</template>

Treats
Calories for
Frozen Yogurt (0)

60 g
Calories for
Eclair (19)

37 g
Calories for
Frozen Yogurt (7)

57 g
Calories for
Frozen Yogurt (18)

35 g
Calories for
Frozen Yogurt (9)

58 g
Calories for
Ice cream sandwich (19)

67 g
Calories for
Frozen Yogurt (20)

49 g
Calories for
Frozen Yogurt (12)

28 g
Calories for
Frozen Yogurt (6)

66 g
每页的行数:
1-9 / 240

然而,如果您想完全自定义内容,请看下面的示例,其中:

  • 我们使用一个 Vue 作用域范围的插槽,叫做 item 来定义每个记录应该如何展示(相当于非网格模式下的行),这样您就可以自由发挥了。
  • 我们开启多选


<template>
  <div class="q-pa-md">
    <q-table
      title="Treats"
      :rows="rows"
      :columns="columns"
      row-key="name"
      selection="multiple"
      v-model:selected="selected"
      :filter="filter"
      grid
      hide-header
    >
      <template v-slot:top-right>
        <q-input borderless dense debounce="300" v-model="filter" placeholder="Search">
          <template v-slot:append>
            <q-icon name="search" />
          </template>
        </q-input>
      </template>

      <template v-slot:item="props">
        <div
          class="q-pa-xs col-xs-12 col-sm-6 col-md-4 col-lg-3 grid-style-transition"
          :style="props.selected ? 'transform: scale(0.95);' : ''"
        >
          <q-card :class="props.selected ? 'bg-grey-2' : ''">
            <q-card-section>
              <q-checkbox dense v-model="props.selected" :label="props.row.name" />
            </q-card-section>
            <q-separator />
            <q-list dense>
              <q-item v-for="col in props.cols.filter(col => col.name !== 'desc')" :key="col.name">
                <q-item-section>
                  <q-item-label>{{ col.label }}</q-item-label>
                </q-item-section>
                <q-item-section side>
                  <q-item-label caption>{{ col.value }}</q-item-label>
                </q-item-section>
              </q-item>
            </q-list>
          </q-card>
        </div>
      </template>

    </q-table>
  </div>
</template>

Treats

Dessert (100g serving)
Frozen Yogurt
Calories
159
Fat (g)
6
Carbs (g)
24
Protein (g)
4
Sodium (mg)
87
Calcium (%)
14%
Iron (%)
1%

Dessert (100g serving)
Ice cream sandwich
Calories
237
Fat (g)
9
Carbs (g)
37
Protein (g)
4.3
Sodium (mg)
129
Calcium (%)
8%
Iron (%)
1%

Dessert (100g serving)
Eclair
Calories
262
Fat (g)
16
Carbs (g)
23
Protein (g)
6
Sodium (mg)
337
Calcium (%)
6%
Iron (%)
7%

Dessert (100g serving)
Cupcake
Calories
305
Fat (g)
3.7
Carbs (g)
67
Protein (g)
4.3
Sodium (mg)
413
Calcium (%)
3%
Iron (%)
8%

Dessert (100g serving)
Gingerbread
Calories
356
Fat (g)
16
Carbs (g)
49
Protein (g)
3.9
Sodium (mg)
327
Calcium (%)
7%
Iron (%)
16%
每页的行数:
1-5 / 10

展开行

WARNING

如果您为一行数据生成了多个 QTr,请为每个 QTr 设置一个唯一的 key



<template>
  <div class="q-pa-md">
    <q-table
      title="Treats"
      :rows="rows"
      :columns="columns"
      row-key="name"
    >

      <template v-slot:header="props">
        <q-tr :props="props">
          <q-th auto-width />
          <q-th
            v-for="col in props.cols"
            :key="col.name"
            :props="props"
          >
            {{ col.label }}
          </q-th>
        </q-tr>
      </template>

      <template v-slot:body="props">
        <q-tr :props="props">
          <q-td auto-width>
            <q-btn size="sm" color="accent" round dense @click="props.expand = !props.expand" :icon="props.expand ? 'remove' : 'add'" />
          </q-td>
          <q-td
            v-for="col in props.cols"
            :key="col.name"
            :props="props"
          >
            {{ col.value }}
          </q-td>
        </q-tr>
        <q-tr v-show="props.expand" :props="props">
          <q-td colspan="100%">
            <div class="text-left">This is expand slot for row above: {{ props.row.name }}.</div>
          </q-td>
        </q-tr>
      </template>

    </q-table>
  </div>
</template>

Treats
Dessert (100g serving)CaloriesFat (g)Carbs (g)Protein (g)Sodium (mg)Calcium (%)Iron (%)
Frozen Yogurt15962448714%1%
Ice cream sandwich2379374.31298%1%
Eclair262162363376%7%
Cupcake3053.7674.34133%8%
Gingerbread35616493.93277%16%
每页的行数:
1-5 / 10

还可以采用外部扩张模式:



<template>
  <div class="q-pa-md">
    <q-table
      title="Treats"
      :rows="rows"
      :columns="columns"
      row-key="name"
      v-model:expanded="expanded"
    >

      <template v-slot:header="props">
        <q-tr :props="props">
          <q-th auto-width />

          <q-th
            v-for="col in props.cols"
            :key="col.name"
            :props="props"
          >
            {{ col.label }}
          </q-th>
        </q-tr>
      </template>

      <template v-slot:body="props">
        <q-tr :props="props">
          <q-td auto-width>
            <q-toggle v-model="props.expand" checked-icon="add" unchecked-icon="remove" />
          </q-td>

          <q-td
            v-for="col in props.cols"
            :key="col.name"
            :props="props"
          >
            {{ col.value }}
          </q-td>
        </q-tr>
        <q-tr v-show="props.expand" :props="props">
          <q-td colspan="100%">
            <div class="text-left">This is expand slot for row above: {{ props.row.name }}.</div>
          </q-td>
        </q-tr>
      </template>

    </q-table>
  </div>
</template>

Treats
Dessert (100g serving)CaloriesFat (g)Carbs (g)Protein (g)Sodium (mg)Calcium (%)Iron (%)
Frozen Yogurt15962448714%1%
Ice cream sandwich2379374.31298%1%
This is expand slot for row above: Ice cream sandwich.
Eclair262162363376%7%
Cupcake3053.7674.34133%8%
Gingerbread35616493.93277%16%
每页的行数:
1-5 / 10

如果您在 QTable 中使用虚拟滚动功能,您应该知道,有两个工具 CSS 类名可以控制虚滚动的大小计算:

  • 使用 q-virtual-scroll--with-prev 类可以使被虚拟滚动渲染的元素与上一个元素一起分组(主要用于从同一行数据生成的多个表行)。
  • 使用 q-virtual-scroll--skip 类可以使被虚拟滚动渲染的元素在计算大小时忽略此元素的大小。


<template>
  <div class="q-pa-md">
    <q-table
      style="height: 400px"
      ref="tableRef"
      title="Treats"
      :rows="rows"
      :columns="columns"
      :table-colspan="9"
      row-key="index"
      virtual-scroll
      :virtual-scroll-item-size="48"
      :pagination="pagination"
      :rows-per-page-options="[0]"
      v-model:expanded="expanded"
    >

      <template v-slot:header="props">
        <q-tr :props="props">
          <q-th auto-width />

          <q-th
            v-for="col in props.cols"
            :key="col.name"
            :props="props"
          >
            {{ col.label }}
          </q-th>
        </q-tr>
      </template>

      <template v-slot:body="props">
        <q-tr :props="props" :key="`m_${props.row.index}`">
          <q-td auto-width>
            <q-toggle v-model="props.expand" checked-icon="add" unchecked-icon="remove" :label="`Index: ${props.row.index}`" />
          </q-td>

          <q-td
            v-for="col in props.cols"
            :key="col.name"
            :props="props"
          >
            {{ col.value }}
          </q-td>
        </q-tr>
        <q-tr v-show="props.expand" :props="props" :key="`e_${props.row.index}`" class="q-virtual-scroll--with-prev">
          <q-td colspan="100%">
            <div class="text-left">This is expand slot for row above: {{ props.row.name }} (Index: {{ props.row.index }}).</div>
          </q-td>
        </q-tr>
      </template>

    </q-table>
  </div>
</template>

Treats
Dessert (100g serving)CaloriesFat (g)Carbs (g)Protein (g)Sodium (mg)Calcium (%)Iron (%)
Index: 4994
Cupcake3053.7674.34133%8%
Index: 4995
Gingerbread35616493.93277%16%
Index: 4996
Jelly bean3750940500%0%
This is expand slot for row above: Jelly bean (Index: 4996).
Index: 4997
Lollipop3920.2980380%2%
Index: 4998
Honeycomb4083.2876.55620%45%
Index: 4999
Donut45225514.93262%22%
This is expand slot for row above: Donut (Index: 4999).
Index: 5000
KitKat518266575412%6%
Index: 5001
Frozen Yogurt15962448714%1%
Index: 5002
Ice cream sandwich2379374.31298%1%
This is expand slot for row above: Ice cream sandwich (Index: 5002).
Index: 5003
Eclair262162363376%7%
Index: 5004
Cupcake3053.7674.34133%8%
Index: 5005
Gingerbread35616493.93277%16%
This is expand slot for row above: Gingerbread (Index: 5005).
Index: 5006
Jelly bean3750940500%0%
Index: 5007
Lollipop3920.2980380%2%
Index: 5008
Honeycomb4083.2876.55620%45%
This is expand slot for row above: Honeycomb (Index: 5008).
Index: 5009
Donut45225514.93262%22%
Index: 5010
KitKat518266575412%6%
Index: 5011
Frozen Yogurt15962448714%1%
This is expand slot for row above: Frozen Yogurt (Index: 5011).
Index: 5012
Ice cream sandwich2379374.31298%1%
Index: 5013
Eclair262162363376%7%
Index: 5014
Cupcake3053.7674.34133%8%
This is expand slot for row above: Cupcake (Index: 5014).
1-10000 / 10000

前/后插槽



<template>
  <div class="q-pa-md">
    <q-table
      title="Treats"
      :rows="rows"
      :columns="columns"
      row-key="name"
      selection="multiple"
      v-model:selected="selected"
    >

      <template v-slot:top>
        Top
      </template>
      <template v-slot:top-row>
        <q-tr>
          <q-td colspan="100%">
            Top row
          </q-td>
        </q-tr>
      </template>

      <template v-slot:bottom-row>
        <q-tr>
          <q-td colspan="100%">
            Bottom row
          </q-td>
        </q-tr>
      </template>

      <template v-slot:bottom>
        Bottom
      </template>

    </q-table>
  </div>
</template>

Top
Dessert (100g serving)CaloriesFat (g)Carbs (g)Protein (g)Sodium (mg)Calcium (%)Iron (%)
Top row
Frozen Yogurt15962448714%1%
Ice cream sandwich2379374.31298%1%
Eclair262162363376%7%
Cupcake3053.7674.34133%8%
Gingerbread35616493.93277%16%
Bottom row
Bottom

分页

TIP

如果 pagination 声明了一个 rowsNumber 属性,那么就代表您为 Table 配置了服务端分页(& 排序 & 筛选)。请参考 服务端分页,排序和筛选 部分。

下面是两个处理分页(以及每页的排序和行数)的示例。

第一个示例强调如何配置基础分页功能:



<template>
  <div class="q-pa-md">
    <q-table
      title="Treats"
      :rows="rows"
      :columns="columns"
      row-key="name"
      :pagination="initialPagination"
    />
  </div>
</template>

Treats
Dessert (100g serving)CaloriesFat (g)Carbs (g)Protein (g)Sodium (mg)Calcium (%)Iron (%)
Frozen Yogurt15962448714%1%
Gingerbread35616493.93277%16%
Honeycomb4083.2876.55620%45%
每页的行数:
4-6 / 10

第二个示例使用 “v-model:pagination” 指令,因为我们希望随时访问它的当前值。以下技术的一个用例是从 QTable 外部控制分页



<template>
  <div class="q-pa-md">
    <q-table
      title="Treats"
      :rows="rows"
      :columns="columns"
      row-key="name"
      v-model:pagination="pagination"
      hide-pagination
    />

    <div class="row justify-center q-mt-md">
      <q-pagination
        v-model="pagination.page"
        color="grey-8"
        :max="pagesNumber"
        size="sm"
      />
    </div>
  </div>
</template>

Treats
Dessert (100g serving)CaloriesFat (g)Carbs (g)Protein (g)
Frozen Yogurt1596244
Gingerbread35616493.9
Honeycomb4083.2876.5

分页插槽

出于学习目的,我们将使用一些基础的控件来实现自定义分页功能,以帮助您开始实现自己的分页控件。



<template>
  <div class="q-pa-md">
    <q-table
      title="Treats"
      :rows="rows"
      :columns="columns"
      row-key="name"
      v-model:pagination="pagination"
    >
      <template v-slot:pagination="scope">
        <q-btn
          v-if="scope.pagesNumber > 2"
          icon="first_page"
          color="grey-8"
          round
          dense
          flat
          :disable="scope.isFirstPage"
          @click="scope.firstPage"
        />

        <q-btn
          icon="chevron_left"
          color="grey-8"
          round
          dense
          flat
          :disable="scope.isFirstPage"
          @click="scope.prevPage"
        />

        <q-btn
          icon="chevron_right"
          color="grey-8"
          round
          dense
          flat
          :disable="scope.isLastPage"
          @click="scope.nextPage"
        />

        <q-btn
          v-if="scope.pagesNumber > 2"
          icon="last_page"
          color="grey-8"
          round
          dense
          flat
          :disable="scope.isLastPage"
          @click="scope.lastPage"
        />
      </template>
    </q-table>
  </div>
</template>

Treats
Dessert (100g serving)CaloriesFat (g)Carbs (g)Protein (g)Sodium (mg)Calcium (%)Iron (%)
Frozen Yogurt15962448714%1%
Gingerbread35616493.93277%16%
Honeycomb4083.2876.55620%45%
每页的行数:

加载状态



<template>
  <div class="q-pa-md">
    <q-toggle v-model="loading" label="Loading state" class="q-mb-md" />
    <q-table
      title="Treats"
      :rows="rows"
      :columns="columns"
      color="primary"
      row-key="name"
      :loading="loading"
    />
  </div>
</template>

Loading state
Treats
Dessert (100g serving)CaloriesFat (g)Carbs (g)Protein (g)Sodium (mg)Calcium (%)Iron (%)
Frozen Yogurt15962448714%1%
Ice cream sandwich2379374.31298%1%
Eclair262162363376%7%
Cupcake3053.7674.34133%8%
Gingerbread35616493.93277%16%
每页的行数:
1-5 / 10


<template>
  <div class="q-pa-md">
    <q-toggle v-model="loading" label="Loading state" class="q-mb-md" />
    <q-table
      title="Treats"
      :rows="rows"
      :columns="columns"
      color="primary"
      row-key="name"
      :loading="loading"
    >
      <template v-slot:loading>
        <q-inner-loading showing color="primary" />
      </template>
    </q-table>
  </div>
</template>

Loading state
Treats
Dessert (100g serving)CaloriesFat (g)Carbs (g)Protein (g)Sodium (mg)Calcium (%)Iron (%)
Frozen Yogurt15962448714%1%
Ice cream sandwich2379374.31298%1%
Eclair262162363376%7%
Cupcake3053.7674.34133%8%
Gingerbread35616493.93277%16%
每页的行数:
1-5 / 10

自定义头部



<template>
  <div class="q-pa-md">
    <q-table
      title="Treats"
      :rows="rows"
      :columns="columns"
      row-key="id"
      :filter="filter"
      :loading="loading"
    >

      <template v-slot:top>
        <q-btn color="primary" :disable="loading" label="Add row" @click="addRow" />
        <q-btn v-if="rows.length !== 0" class="q-ml-sm" color="primary" :disable="loading" label="Remove row" @click="removeRow" />
        <q-space />
        <q-input borderless dense debounce="300" color="primary" v-model="filter">
          <template v-slot:append>
            <q-icon name="search" />
          </template>
        </q-input>
      </template>

    </q-table>
  </div>
</template>

Dessert (100g serving)CaloriesFat (g)Carbs (g)Protein (g)Sodium (mg)Calcium (%)Iron (%)
Frozen Yogurt15962448714%1%
Ice cream sandwich2379374.31298%1%
Eclair262162363376%7%
Cupcake3053.7674.34133%8%
Gingerbread35616493.93277%16%
每页的行数:
1-5 / 10

Body 插槽

下面的示例显示了如何使用插槽自定义整个行:



<template>
  <div class="q-pa-md">
    <q-table
      title="Treats"
      :rows="rows"
      :columns="columns"
      row-key="name"
    >
      <template v-slot:body="props">
        <q-tr :props="props">
          <q-td key="name" :props="props">
            {{ props.row.name }}
          </q-td>
          <q-td key="calories" :props="props">
            <q-badge color="green">
              {{ props.row.calories }}
            </q-badge>
          </q-td>
          <q-td key="fat" :props="props">
            <q-badge color="purple">
              {{ props.row.fat }}
            </q-badge>
          </q-td>
          <q-td key="carbs" :props="props">
            <q-badge color="orange">
              {{ props.row.carbs }}
            </q-badge>
          </q-td>
          <q-td key="protein" :props="props">
            <q-badge color="primary">
              {{ props.row.protein }}
            </q-badge>
          </q-td>
          <q-td key="sodium" :props="props">
            <q-badge color="teal">
              {{ props.row.sodium }}
            </q-badge>
          </q-td>
          <q-td key="calcium" :props="props">
            <q-badge color="accent">
              {{ props.row.calcium }}
            </q-badge>
          </q-td>
          <q-td key="iron" :props="props">
            <q-badge color="amber">
              {{ props.row.iron }}
            </q-badge>
          </q-td>
        </q-tr>
      </template>
    </q-table>
  </div>
</template>

Treats
Dessert (100g serving)CaloriesFat (g)Carbs (g)Protein (g)Sodium (mg)Calcium (%)Iron (%)
Frozen Yogurt
159
6
24
4
87
14%
1%
Ice cream sandwich
237
9
37
4.3
129
8%
1%
Eclair
262
16
23
6
337
6%
7%
Cupcake
305
3.7
67
4.3
413
3%
8%
Gingerbread
356
16
49
3.9
327
7%
16%
每页的行数:
1-5 / 10

下面我们使用一个会被应用到每个单元格的插槽:



<template>
  <div class="q-pa-md">
    <q-table
      title="Treats"
      :rows="rows"
      :columns="columns"
      row-key="name"
    >
      <template v-slot:body-cell="props">
        <q-td :props="props">
          <q-badge color="blue" :label="props.value" />
        </q-td>
      </template>
    </q-table>
  </div>
</template>

Treats
Dessert (100g serving)CaloriesFat (g)Carbs (g)Protein (g)Sodium (mg)Calcium (%)Iron (%)
Frozen Yogurt
159
6
24
4
87
14%
1%
Ice cream sandwich
237
9
37
4.3
129
8%
1%
Eclair
262
16
23
6
337
6%
7%
Cupcake
305
3.7
67
4.3
413
3%
8%
Gingerbread
356
16
49
3.9
327
7%
16%
每页的行数:
1-5 / 10

我们也可以指定自定义某些特殊的列。这种插槽的写法是 body-cell-[name],其中 [name] 应该被替换成行中用作 row-key 的属性。



<template>
  <div class="q-pa-md">
    <q-table
      title="Treats"
      :rows="rows"
      :columns="columns"
      row-key="name"
    >
      <template v-slot:body-cell-name="props">
        <q-td :props="props">
          <div>
            <q-badge color="purple" :label="props.value" />
          </div>
          <div class="my-table-details">
            {{ props.row.details }}
          </div>
        </q-td>
      </template>
    </q-table>
  </div>
</template>

Treats
Dessert (100g serving)CaloriesFat (g)Carbs (g)Protein (g)Sodium (mg)Calcium (%)Iron (%)
Frozen Yogurt
15962448714%1%
Ice cream sandwich
2379374.31298%1%
Eclair
262162363376%7%
Cupcake
3053.7674.34133%8%
Gingerbread
35616493.93277%16%
每页的行数:
1-5 / 10

Header 插槽

下面的示例显示了如何使用槽自定义整个标题行



<template>
  <div class="q-pa-md">
    <q-table
      title="Treats"
      :rows="rows"
      :columns="columns"
      row-key="name"
    >
      <template v-slot:header="props">
        <q-tr :props="props">
          <q-th
            v-for="col in props.cols"
            :key="col.name"
            :props="props"
            class="text-italic text-purple"
          >
            {{ col.label }}
          </q-th>
        </q-tr>
      </template>
    </q-table>
  </div>
</template>

Treats
Dessert (100g serving)CaloriesFat (g)Carbs (g)Protein (g)Sodium (mg)Calcium (%)Iron (%)
Frozen Yogurt15962448714%1%
Ice cream sandwich2379374.31298%1%
Eclair262162363376%7%
Cupcake3053.7674.34133%8%
Gingerbread35616493.93277%16%
每页的行数:
1-5 / 10

下面我们使用一个会被应用于每个表头单元格的插槽:



<template>
  <div class="q-pa-md">
    <q-table
      title="Treats"
      :rows="rows"
      :columns="columns"
      row-key="name"
    >
      <template v-slot:header-cell="props">
        <q-th :props="props">
          <q-icon name="lock_open" size="1.5em" />
          {{ props.col.label }}
        </q-th>
      </template>
    </q-table>
  </div>
</template>

Treats
Dessert (100g serving) Calories Fat (g) Carbs (g) Protein (g) Sodium (mg) Calcium (%) Iron (%)
Frozen Yogurt15962448714%1%
Ice cream sandwich2379374.31298%1%
Eclair262162363376%7%
Cupcake3053.7674.34133%8%
Gingerbread35616493.93277%16%
每页的行数:
1-5 / 10

我们也可以指定自定义某些特殊的表头单元格。这种插槽的写法是 header-cell-[name],其中 [name] 应该被替换成行中用作 row-key 的属性。



<template>
  <div class="q-pa-md">
    <q-table
      title="Treats"
      :rows="rows"
      :columns="columns"
      row-key="name"
    >
      <template v-slot:header-cell-calories="props">
        <q-th :props="props">
          <q-icon name="thumb_up" size="1.5em" />
          {{ props.col.label }}
        </q-th>
      </template>
    </q-table>
  </div>
</template>

Treats
Dessert (100g serving) CaloriesFat (g)Carbs (g)Protein (g)Sodium (mg)Calcium (%)Iron (%)
Frozen Yogurt15962448714%1%
Ice cream sandwich2379374.31298%1%
Eclair262162363376%7%
Cupcake3053.7674.34133%8%
Gingerbread35616493.93277%16%
每页的行数:
1-5 / 10

空数据



<template>
  <div class="q-pa-md">
    <q-table
      title="Treats"
      :rows="rows"
      :columns="columns"
      no-data-label="I didn't find anything for you"
      row-key="name"
    />
  </div>
</template>

Treats
Dessert (100g serving)CaloriesFat (g)Carbs (g)Protein (g)Sodium (mg)Calcium (%)Iron (%)
I didn't find anything for you

当表格没有数据可以展示时,您也可以使用空数据插槽 (“no-data”) 来自定义要展示的消息。也可以在 “Search” 输入框中输入一些数据。



<template>
  <div class="q-pa-md">
    <q-table
      title="Treats"
      :rows="rows"
      :columns="columns"
      :filter="filter"
      no-data-label="I didn't find anything for you"
      no-results-label="The filter didn't uncover any results"
      row-key="name"
    >
      <template v-slot:top-right>
        <q-input borderless dense debounce="300" v-model="filter" placeholder="Search">
          <template v-slot:append>
            <q-icon name="search" />
          </template>
        </q-input>
      </template>

      <template v-slot:no-data="{ icon, message, filter }">
        <div class="full-width row flex-center text-accent q-gutter-sm">
          <q-icon size="2em" name="sentiment_dissatisfied" />
          <span>
            Well this is sad... {{ message }}
          </span>
          <q-icon size="2em" :name="filter ? 'filter_b_and_w' : icon" />
        </div>
      </template>
    </q-table>
  </div>
</template>

Treats
Dessert (100g serving)CaloriesFat (g)Carbs (g)Protein (g)Sodium (mg)Calcium (%)Iron (%)
Well this is sad... I didn't find anything for you

处理底层

有一些属性可以用于隐藏底部区域的一些部分,下面有一些示例:



<template>
  <div class="q-pa-md">
    <div class="row items-center q-gutter-sm q-mb-md">
      <q-toggle label="Fill with data" v-model="hasData" />
      <q-toggle label="Hide no data" v-model="hideNoData" />
      <q-toggle label="Hide bottom layer" v-model="hideBottom" />
      <q-toggle label="Hide pagination" v-model="hidePagination" />
      <q-toggle label="Hide selected rows banner" v-model="hideSelectedBanner" />
    </div>

    <q-table
      title="Treats"
      :rows="records"
      :columns="columns"
      row-key="name"
      selection="multiple"
      v-model:selected="selected"
      :hide-bottom="hideBottom"
      :hide-selected-banner="hideSelectedBanner"
      :hide-no-data="hideNoData"
      :hide-pagination="hidePagination"
    />
  </div>
</template>

Fill with data
Hide no data
Hide bottom layer
Hide pagination
Hide selected rows banner
Treats
Dessert (100g serving)CaloriesFat (g)Carbs (g)
Frozen Yogurt159624
Ice cream sandwich237937
Eclair2621623
Cupcake3053.767
Gingerbread3561649
已选择1行
每页的行数:
1-5 / 10

自定义排序



<template>
  <div class="q-pa-md">
    <q-table
      title="Treats"
      :rows="rows"
      :columns="columns"
      row-key="name"
      :sort-method="customSort"
      binary-state-sort
    />
  </div>
</template>

Treats
Dessert (100g serving)CaloriesFat (g)Carbs (g)Protein (g)Sodium (mg)Calcium (%)Iron (%)
Frozen Yogurt15962448714%1%
Ice cream sandwich2379374.31298%1%
Eclair262162363376%7%
Cupcake3053.7674.34133%8%
Gingerbread35616493.93277%16%
每页的行数:
1-5 / 10

响应式表格

为了实现响应式表格,我们有两个工具可以使用:densegrid 属性。我们还可以将其与 $q.screen 搭配使用,更多信息请参考:屏幕插件

下面的第一个示例使用了 $q.screen.lt.md 来开启紧凑模式,第二个示例使用了 $q.screen.xs 来开启网格模式,所以您需要调整浏览器的窗口大小来查看它们的变化。



<template>
  <div class="q-pa-md">
    <q-table
      :dense="$q.screen.lt.md"
      title="Treats"
      :rows="rows"
      :columns="columns"
      row-key="name"
    />
  </div>
</template>

Treats
Dessert (100g serving)CaloriesFat (g)Carbs (g)Protein (g)Sodium (mg)Calcium (%)Iron (%)
Frozen Yogurt15962448714%1%
Ice cream sandwich2379374.31298%1%
Eclair262162363376%7%
Cupcake3053.7674.34133%8%
Gingerbread35616493.93277%16%
每页的行数:
1-5 / 10


<template>
  <div class="q-pa-md">
    <q-table
      :grid="$q.screen.xs"
      title="Treats"
      :rows="rows"
      :columns="columns"
      row-key="name"
      :filter="filter"
      hide-header
    >
      <template v-slot:top-right>
        <q-input borderless dense debounce="300" v-model="filter" placeholder="Search">
          <template v-slot:append>
            <q-icon name="search" />
          </template>
        </q-input>
      </template>
    </q-table>
  </div>
</template>

Treats
Frozen Yogurt159624
Ice cream sandwich237937
Eclair2621623
Cupcake3053.767
Gingerbread3561649
每页的行数:
1-5 / 10

服务端分页,排序和筛选

当您的数据库中拥有大量的数据时,出于内存,UI 渲染性能等原因,很明显不能一次性全部加载它们。您可以一次只加载表格的一页数据,当用户想要访问下一页数据,或者想要重新排序/筛选时,再去服务端重新请求对应的数据。

  1. 要开启这个行为的第一步是声明 pagination 属性,并且其中必须包括 rowsNumber 字段。QTable 需要知道可用的行总数,以便正确渲染分页控件。如果筛选导致 rowsNumber 更改,则必须动态修改它。

  2. 第二步是监听 QTable 的 @request 事件。如果因为页码,筛选或者排序的改变需要重新去服务端重新请求数据时,这个事件会被触发。

  3. 最好声明 loading 属性来告知用户,后台正在请求数据。

TIP

在下面的示例中,模拟了使用 ajax 对服务器进行请求的步骤。虽然概念相似,但如果您要使用此代码,还需要进行适当的更改以连接到您自己的数据源。



<template>
  <div class="q-pa-md">
    <q-table
      title="Treats"
      :rows="rows"
      :columns="columns"
      row-key="id"
      v-model:pagination="pagination"
      :loading="loading"
      :filter="filter"
      @request="onRequest"
      binary-state-sort
    >
      <template v-slot:top-right>
        <q-input borderless dense debounce="300" v-model="filter" placeholder="Search">
          <template v-slot:append>
            <q-icon name="search" />
          </template>
        </q-input>
      </template>

    </q-table>
  </div>
</template>

Treats
Dessert (100g serving)CaloriesFat (g)Carbs (g)Protein (g)Sodium (mg)Calcium (%)Iron (%)
正在加载...

导出数据

下面是一个简单的 csv 编码示例,然后使用 Quasar 提供的 exportFile 工具函数导出表格数据,浏览器应该会触发一个文件下载。对于更专业的编码方法,我们建议使用 csv-parsecsv-stringify 包。

提示

如果要导出用户筛选 + 排序的数据,还可以使用 QTable 内部的 filteredSortedRows 计算属性。



<template>
  <div class="q-pa-md">
    <q-table
      title="Treats"
      :rows="rows"
      :columns="columns"
      color="primary"
      row-key="name"
    >
      <template v-slot:top-right>
        <q-btn
          color="primary"
          icon-right="archive"
          label="Export to csv"
          no-caps
          @click="exportTable"
        />
      </template>
    </q-table>
  </div>
</template>

Treats
Dessert (100g serving)CaloriesFat (g)Carbs (g)Protein (g)Sodium (mg)Calcium (%)Iron (%)
Frozen Yogurt15962448714%1%
Ice cream sandwich2379374.31298%1%
Eclair262162363376%7%
Cupcake3053.7674.34133%8%
Gingerbread35616493.93277%16%
每页的行数:
1-5 / 10

键盘导航

下面是一个使用键盘在表格所选行中导航的示例。使用 ArrowUpArrowDownPageUpPageDownHomeEnd 键进行导航。



<template>
  <div class="q-pa-md">
    <q-table
      ref="tableRef"
      :class="tableClass"
      tabindex="0"
      title="Treats"
      :rows="rows"
      :columns="columns"
      row-key="name"
      selection="single"
      v-model:selected="selected"
      v-model:pagination="pagination"
      :filter="filter"
      @focusin="activateNavigation"
      @focusout="deactivateNavigation"
      @keydown="onKey"
    >
      <template v-slot:top-right>
        <q-input borderless dense debounce="300" v-model="filter" placeholder="Search">
          <template v-slot:append>
            <q-icon name="search" />
          </template>
        </q-input>
      </template>
    </q-table>
  </div>
</template>

Treats
Dessert (100g serving)CaloriesFat (g)Carbs (g)Protein (g)Sodium (mg)Calcium (%)Iron (%)
Frozen Yogurt15962448714%1%
Ice cream sandwich2379374.31298%1%
Eclair262162363376%7%
Cupcake3053.7674.34133%8%
Gingerbread35616493.93277%16%
每页的行数:
1-5 / 40

类型定义

export type QTableColumn<
  Row extends Record<string, any> = any,
  Key = keyof Row extends string ? keyof Row : string,
  Field = Key | ((row: Row) => any),
> = Omit<NonNullable<QTableProps["columns"]>[number], "field" | "format"> & {
  field: Field;
  format?: (val: any, row: Row) => string;
};