Skip to content

DataTablePaginator

Visão geral

O componente LxDataTablePaginator oferece controles de navegação para tabelas paginadas. Exibe o seletor de itens por página, o intervalo atual de registros e botões de navegação (primeira, anterior, numeradas, próxima, última).

É totalmente responsivo — em telas menores os elementos menos essenciais são ocultados progressivamente — e acessível, com ARIA labels em todos os controles.


Modos de uso

O LxDataTablePaginator pode ser utilizado de duas formas:

1. Integrado com LxDataTable (Modo Recomendado)

Ideal quando você deseja controlar a paginação de um LxDataTable externamente. Ao usar o slot paginator, o LxDataTable desabilita automaticamente o paginador nativo e usa o LxDataTablePaginator como controlador:

vue
<LxDataTable :value="dadosPaginados">
  <!-- Colunas aqui -->
</LxDataTable>

<LxDataTablePaginator
  :total-items="totalItems"
  :current-page="currentPage"
  @update:pagination="handlePaginationUpdate"
/>

Ou via slot paginator do LxDataTable:

vue
<LxDataTable :value="dadosPaginados">
  <!-- Colunas aqui -->
  
  <template #paginator>
    <LxDataTablePaginator
      :total-items="totalItems"
      :current-page="currentPage"
      @update:pagination="handlePaginationUpdate"
    />
  </template>
</LxDataTable>

2. Isolado (Tabela Manual)

Pode ser utilizado para paginar qualquer tipo de tabela HTML ou lista customizada, sem depender do LxDataTable:

vue
<table>
  <!-- Renderizar apenas os dados da página atual -->
</table>

<LxDataTablePaginator
  :total-items="totalItems"
  :current-page="currentPage"
  @update:pagination="handlePaginationUpdate"
/>

Exemplo com LxDataTable

Clique para visualizar o código
vue
<script setup>
import { ref, computed } from 'vue';
import { LxDataTable, LxDataTableColumn, LxDataTablePaginator } from '@lde/lxcomponents';

const currentPage = ref(1);
const itemsPerPage = ref(20);
const totalItems = 156;

const statuses = ['Aprovado', 'Pendente', 'Rejeitado', 'Rascunho'];
const categories = ['Eletrônicos', 'Alimentação', 'Vestuário', 'Casa', 'Esportes'];

const allData = Array.from({ length: totalItems }, (_, i) => ({
	id: 1000 + i + 1,
	produto: `Produto ${String(i + 1).padStart(3, '0')}`,
	categoria: categories[i % categories.length],
	preco: (i + 1) * 7.5 + 10,
	quantidade: ((i * 37) % 500) + 1,
	status: statuses[i % statuses.length]
}));

const dadosPaginados = computed(() => {
	const start = (currentPage.value - 1) * itemsPerPage.value;
	return allData.slice(start, start + itemsPerPage.value);
});

const handlePaginationUpdate = ({ currentPage: page, itemsPerPage: perPage }) => {
	currentPage.value = page;
	itemsPerPage.value = perPage;
};

const formatCurrency = (value) => {
	return new Intl.NumberFormat('pt-BR', { style: 'currency', currency: 'BRL' }).format(value);
};

const statusClass = (status) =>
	({
		Aprovado: 'text-bg-success',
		Pendente: 'text-bg-warning',
		Rejeitado: 'text-bg-danger',
		Rascunho: 'text-bg-secondary'
	})[status] ?? 'text-bg-secondary';
</script>

<template>
	<div>
		<LxDataTable :value="dadosPaginados" data-key="id" :pagination-config="{ paginator: false }">
			<LxDataTableColumn field="id" header="ID" header-style="width: 80px" />
			<LxDataTableColumn field="produto" header="Produto" />
			<LxDataTableColumn field="categoria" header="Categoria" />
			<LxDataTableColumn field="preco" header="Preço" header-style="text-align: right">
				<template #body="{ data }">
					{{ formatCurrency(data.preco) }}
				</template>
			</LxDataTableColumn>
			<LxDataTableColumn field="quantidade" header="Qtd." header-style="text-align: center; width: 80px" />
			<LxDataTableColumn field="status" header="Status" header-style="text-align: center; width: 120px">
				<template #body="{ data }">
					<span class="badge" :class="statusClass(data.status)">{{ data.status }}</span>
				</template>
			</LxDataTableColumn>
		</LxDataTable>

		<LxDataTablePaginator
			:total-items="totalItems"
			:current-page="currentPage"
			:items-per-page="itemsPerPage"
			:page-options="[10, 20, 50, 100]"
			@update:pagination="handlePaginationUpdate"
		/>
	</div>
</template>

Propriedades

NomeDescriçãoTipoPadrão
totalItemsTotal de itens a paginarNumberrequired
currentPagePágina atual (1-indexed)Number1
itemsPerPageItens exibidos por páginaNumber10
pageOptionsOpções de itens por página no dropdownNumber[][10, 20, 30, 50, 100]
disabledDesabilita toda a navegaçãoBooleanfalse
showPageButtonsExibe botões de páginas numeradasBooleantrue
showLabelExibe a label "Mostrar" ao lado do seletorBooleantrue
textAlignAlinhamento do paginator (left, center, right)String'center'
compactModo compacto — oculta elementos auxiliares em telas pequenasBooleanfalse
sizeTamanho do componente (sm, md, lg)String'md'
maxVisiblePagesNúmero máximo de botões paginados visíveis (deve ser ímpar e ≥ 3)Number5

Eventos

NomeDescriçãoPayload
update:paginationEmitido ao mudar de página ou alterar itens por página{ currentPage: number, itemsPerPage: number, totalItems: number }

Responsividade

BreakpointComportamento
> 960pxExibição completa
≤ 960pxOculta a label "Mostrar" e páginas não-adjacentes
≤ 768pxOculta também o seletor de itens e o intervalo de página
altura < 700pxReduz automaticamente o tamanho dos elementos

Playground

NomeControle
Clique para exibir o código
vue
<script setup>
import { reactive, ref } from 'vue';
import { LxDataTablePaginator } from '@lde/lxcomponents';

const paginacao = reactive({
	currentPage: 1,
	itemsPerPage: 10,
	totalItems: 100
});

const props = reactive({
	disabled: false,
	showPageButtons: true,
	showLabel: true,
	textAlign: 'center',
	compact: false,
	size: 'md',
	maxVisiblePages: 5
});

const pageOptionsInput = ref('10,20,30,50,100');

const pageOptions = reactive([10, 20, 30, 50, 100]);

const syncPageOptions = () => {
	const parsed = pageOptionsInput.value
		.split(',')
		.map((v) => parseInt(v.trim()))
		.filter((v) => !isNaN(v) && v > 0);
	pageOptions.splice(0, pageOptions.length, ...parsed);
};

const handlePaginationUpdate = ({ currentPage, itemsPerPage }) => {
	paginacao.currentPage = currentPage;
	paginacao.itemsPerPage = itemsPerPage;
};
</script>

<template>
	<div>
		<!-- Resultado -->
		<div class="border p-3 rounded mb-3 bg-white">
			<LxDataTablePaginator
				:total-items="paginacao.totalItems"
				:current-page="paginacao.currentPage"
				:items-per-page="paginacao.itemsPerPage"
				:page-options="pageOptions"
				:disabled="props.disabled"
				:show-page-buttons="props.showPageButtons"
				:show-label="props.showLabel"
				:text-align="props.textAlign"
				:compact="props.compact"
				:size="props.size"
				:max-visible-pages="props.maxVisiblePages"
				@update:pagination="handlePaginationUpdate"
			/>
		</div>

		<!-- Controles -->
		<table>
			<thead>
				<tr>
					<th style="width: 150px">Nome</th>
					<th>Controle</th>
				</tr>
			</thead>
			<tbody>
				<tr>
					<td><label class="form-label m-0">totalItems</label></td>
					<td><input v-model.number="paginacao.totalItems" type="number" class="form-control form-control-sm" min="0" /></td>
				</tr>
				<tr>
					<td><label class="form-label m-0">currentPage</label></td>
					<td><input v-model.number="paginacao.currentPage" type="number" class="form-control form-control-sm" min="1" /></td>
				</tr>
				<tr>
					<td><label class="form-label m-0">itemsPerPage</label></td>
					<td><input v-model.number="paginacao.itemsPerPage" type="number" class="form-control form-control-sm" min="1" /></td>
				</tr>
				<tr>
					<td><label class="form-label m-0">pageOptions</label></td>
					<td>
						<input v-model="pageOptionsInput" type="text" class="form-control form-control-sm" placeholder="10,20,50" @change="syncPageOptions" />
					</td>
				</tr>
				<tr>
					<td><label class="form-label m-0">size</label></td>
					<td>
						<select v-model="props.size" class="form-select form-select-sm">
							<option value="sm">sm</option>
							<option value="md">md</option>
							<option value="lg">lg</option>
						</select>
					</td>
				</tr>
				<tr>
					<td><label class="form-label m-0">textAlign</label></td>
					<td>
						<select v-model="props.textAlign" class="form-select form-select-sm">
							<option value="left">left</option>
							<option value="center">center</option>
							<option value="right">right</option>
						</select>
					</td>
				</tr>
				<tr>
					<td><label class="form-label m-0">maxVisiblePages</label></td>
					<td>
						<select v-model.number="props.maxVisiblePages" class="form-select form-select-sm">
							<option :value="3">3</option>
							<option :value="5">5</option>
							<option :value="7">7</option>
							<option :value="9">9</option>
						</select>
					</td>
				</tr>
				<tr>
					<td><label class="form-label m-0">disabled</label></td>
					<td><input v-model="props.disabled" class="form-check-input" type="checkbox" /></td>
				</tr>
				<tr>
					<td><label class="form-label m-0">showLabel</label></td>
					<td><input v-model="props.showLabel" class="form-check-input" type="checkbox" /></td>
				</tr>
				<tr>
					<td><label class="form-label m-0">showPageButtons</label></td>
					<td><input v-model="props.showPageButtons" class="form-check-input" type="checkbox" /></td>
				</tr>
				<tr>
					<td><label class="form-label m-0">compact</label></td>
					<td><input v-model="props.compact" class="form-check-input" type="checkbox" /></td>
				</tr>
			</tbody>
		</table>
	</div>
</template>

Desenvolvido pelo time Linx Microvix