feat: 新增组件
This commit is contained in:
@@ -1,135 +1,49 @@
|
||||
<template>
|
||||
<div class="flex items-center justify-between pt-[20px]">
|
||||
<div class="text-sm text-gray-600">共 {{ total }} 项数据</div>
|
||||
<div class="flex items-center gap-2">
|
||||
<SelectRoot v-model="selectedCount" v-model:open="open">
|
||||
<SelectTrigger class="inline-flex items-center justify-between rounded-md border border-gray-200 bg-white px-3 py-1 text-sm text-gray-700 shadow-sm hover:bg-gray-50">
|
||||
<span>{{ selectedCount }} 条/页</span>
|
||||
<RiArrowDownSLine />
|
||||
</SelectTrigger>
|
||||
|
||||
<SelectPortal :to="portalTarget">
|
||||
<SelectContent position="popper" :side-offset="6" class="z-50 rounded-md border border-gray-200 bg-white shadow-lg" :style="{ minWidth: 'var(--radix-select-trigger-width)' }">
|
||||
<SelectViewport class="p-1">
|
||||
<SelectGroup>
|
||||
<SelectItem v-for="(option, index) in pageSizes" :key="index" :value="String(option)" class="flex cursor-pointer select-none items-center rounded px-2 py-1 text-sm text-gray-700 hover:bg-gray-50">
|
||||
<SelectItemText>{{ option }} 条/页</SelectItemText>
|
||||
</SelectItem>
|
||||
</SelectGroup>
|
||||
</SelectViewport>
|
||||
</SelectContent>
|
||||
</SelectPortal>
|
||||
</SelectRoot>
|
||||
|
||||
<PaginationRoot
|
||||
v-model:page="currentPage"
|
||||
:total="total"
|
||||
:items-per-page="Number(selectedCount)"
|
||||
show-edges
|
||||
:sibling-count="1"
|
||||
:default-page="currentPage"
|
||||
>
|
||||
<PaginationList
|
||||
v-slot="{ items }"
|
||||
class="flex items-center gap-1 text-[#171717]"
|
||||
>
|
||||
<PaginationPrev aria-label="上一页" class="w-9 h-9 flex items-center justify-center mr-4 border rounded bg-white text-gray-700 disabled:opacity-50">
|
||||
<RiArrowLeftLine size="18" />
|
||||
</PaginationPrev>
|
||||
<template v-for="(page, index) in items">
|
||||
<PaginationListItem
|
||||
v-if="page.type === 'page'"
|
||||
:key="index"
|
||||
class="w-9 h-9 border rounded transition data-[selected]:bg-blue-600 data-[selected]:text-white hover:bg-white/10"
|
||||
:value="page.value"
|
||||
>
|
||||
{{ page.value }}
|
||||
</PaginationListItem>
|
||||
<PaginationEllipsis
|
||||
v-else
|
||||
:key="page.type"
|
||||
:index="index"
|
||||
class="w-9 h-9 flex items-center justify-center"
|
||||
>
|
||||
…
|
||||
</PaginationEllipsis>
|
||||
</template>
|
||||
<PaginationNext aria-label="下一页" class="w-9 h-9 flex items-center justify-center ml-4 border rounded bg-white text-gray-700 disabled:opacity-50 focus-within:outline focus-within:outline-1 focus-within:outline-offset-1">
|
||||
<RiArrowRightLine size="18" />
|
||||
</PaginationNext>
|
||||
</PaginationList>
|
||||
</PaginationRoot>
|
||||
|
||||
<div class="ml-2 flex items-center gap-2 text-sm text-gray-700">
|
||||
<span>跳至</span>
|
||||
<input
|
||||
class="w-[55px] rounded border border-gray-200 bg-white px-2 py-1 text-center outline-none focus:border-blue-500"
|
||||
type="text"
|
||||
:min="1"
|
||||
:max="pageTotal"
|
||||
v-model.number="jumpValue"
|
||||
@keydown.enter="onJump"
|
||||
@blur="onJump"
|
||||
/>
|
||||
<span>/ {{ pageTotal }} 页</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<el-pagination @size-change="sizeChangeHandle" @current-change="currentChangeHandle" class="mt-[15px]"
|
||||
:pager-count="5" :page-sizes="pageSizes" :current-page="current" background :page-size="size" :layout="layout"
|
||||
:total="total">
|
||||
</el-pagination>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="Pagination">
|
||||
import { ref, defineProps, defineEmits, watch, onMounted, computed } from 'vue'
|
||||
import { RiArrowLeftLine, RiArrowRightLine, RiArrowDownSLine } from '@remixicon/vue'
|
||||
import { SelectRoot, SelectTrigger, SelectPortal, SelectContent, SelectViewport, SelectGroup, SelectItem, SelectItemText, PaginationRoot, PaginationList, PaginationPrev, PaginationListItem, PaginationEllipsis, PaginationNext } from 'radix-vue'
|
||||
import { PaginationProps, EmitsProps } from '@/types'
|
||||
<script setup lang="ts" name="pagination">
|
||||
const emit = defineEmits(['sizeChange', 'currentChange']);
|
||||
|
||||
const props = defineProps<PaginationProps>()
|
||||
const emit = defineEmits<EmitsProps>()
|
||||
|
||||
const pageSizes = ref(Array.isArray(props.pageSizes) && props.pageSizes.length ? props.pageSizes : [10, 20, 50, 100, 200])
|
||||
const selectedCount = ref(String(props.pageSize ?? pageSizes.value[0]))
|
||||
const open = ref(false)
|
||||
const portalTarget = typeof document !== 'undefined' ? document.body : undefined
|
||||
watch(() => props.pageSize, (val) => selectedCount.value = String(val))
|
||||
watch(selectedCount, (val) => emit('update:pageSize', val))
|
||||
watch(open, (val) => {
|
||||
console.log('Select open state:', val)
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
console.log('Select initial value:', selectedCount.value)
|
||||
})
|
||||
const pageTotal = computed(() => {
|
||||
const t = Number(props.total || 0)
|
||||
const s = Number(selectedCount.value || props.pageSize || 10)
|
||||
const pages = s > 0 ? Math.ceil(t / s) : 1
|
||||
return Math.max(1, pages)
|
||||
})
|
||||
watch(pageTotal, (val) => {
|
||||
console.log('Pagination total pages:', val, 'from total items:', props.total, 'pageSize:', selectedCount.value)
|
||||
})
|
||||
|
||||
// 跳转分页
|
||||
const jumpValue = ref()
|
||||
const onJump = () => {
|
||||
const v = Number(jumpValue.value)
|
||||
if (!Number.isFinite(v)) return
|
||||
const clamped = Math.max(1, Math.min(pageTotal.value, v))
|
||||
jumpValue.value = clamped
|
||||
currentPage.value = clamped
|
||||
emit('update:currentPage', clamped)
|
||||
emit('currentChange', clamped)
|
||||
}
|
||||
|
||||
const currentPage = ref(props.currentPage ?? 1)
|
||||
watch(() => props.currentPage, (val) => {
|
||||
if (typeof val === 'number' && Number.isFinite(val)) currentPage.value = val
|
||||
})
|
||||
watch(currentPage, (p) => {
|
||||
emit('update:currentPage', p)
|
||||
emit('currentChange', p)
|
||||
})
|
||||
const props = defineProps({
|
||||
current: {
|
||||
type: Number,
|
||||
default: 1,
|
||||
},
|
||||
size: {
|
||||
type: Number,
|
||||
default: 10,
|
||||
},
|
||||
total: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
pageSizes: {
|
||||
type: Array as () => number[],
|
||||
default: () => {
|
||||
return [10, 20, 50, 100, 200];
|
||||
},
|
||||
},
|
||||
layout: {
|
||||
type: String,
|
||||
default: 'total, sizes, prev, pager, next, jumper',
|
||||
},
|
||||
});
|
||||
// 分页改变
|
||||
const sizeChangeHandle = (val: number) => {
|
||||
emit('sizeChange', val);
|
||||
};
|
||||
// 分页改变
|
||||
const currentChangeHandle = (val: number) => {
|
||||
emit('currentChange', val);
|
||||
};
|
||||
</script>
|
||||
|
||||
<style></style>
|
||||
<style scoped>
|
||||
:deep(.el-pagination__sizes) {
|
||||
margin-left: auto;
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user