小程序初始提交
This commit is contained in:
@@ -0,0 +1,256 @@
|
||||
<template>
|
||||
<view class="cl-pagination">
|
||||
<view
|
||||
class="cl-pagination__prev"
|
||||
:class="[
|
||||
{
|
||||
'is-disabled': value == 1,
|
||||
'is-dark': isDark
|
||||
},
|
||||
pt.item?.className,
|
||||
pt.prev?.className
|
||||
]"
|
||||
@tap="prev"
|
||||
>
|
||||
<slot name="prev" :disabled="value == 1">
|
||||
<cl-icon
|
||||
:name="pt.prevIcon?.name ?? 'arrow-left-s-line'"
|
||||
:size="pt.prevIcon?.size"
|
||||
:color="pt.prevIcon?.color"
|
||||
:pt="{
|
||||
className: pt.prevIcon?.className
|
||||
}"
|
||||
></cl-icon>
|
||||
</slot>
|
||||
</view>
|
||||
|
||||
<view
|
||||
v-for="(item, index) in list"
|
||||
:key="index"
|
||||
class="cl-pagination__item"
|
||||
:class="[
|
||||
{
|
||||
'is-active': item == value,
|
||||
'is-dark': isDark
|
||||
},
|
||||
pt.item?.className
|
||||
]"
|
||||
@tap="toPage(item)"
|
||||
>
|
||||
<cl-text
|
||||
:pt="{
|
||||
className: parseClass([
|
||||
'cl-pagination__item-text',
|
||||
{
|
||||
'text-white': item == value
|
||||
},
|
||||
pt.itemText?.className
|
||||
])
|
||||
}"
|
||||
>{{ item }}</cl-text
|
||||
>
|
||||
</view>
|
||||
|
||||
<view
|
||||
class="cl-pagination__next"
|
||||
:class="[
|
||||
{
|
||||
'is-disabled': value == totalPage,
|
||||
'is-dark': isDark
|
||||
},
|
||||
pt.item?.className,
|
||||
pt.next?.className
|
||||
]"
|
||||
@tap="next"
|
||||
>
|
||||
<slot name="next" :disabled="value == totalPage">
|
||||
<cl-icon
|
||||
:name="pt.nextIcon?.name ?? 'arrow-right-s-line'"
|
||||
:size="pt.nextIcon?.size"
|
||||
:color="pt.nextIcon?.color"
|
||||
:pt="{
|
||||
className: pt.nextIcon?.className
|
||||
}"
|
||||
></cl-icon>
|
||||
</slot>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import type { PassThroughProps } from "../../types";
|
||||
import { isDark, parseClass, parsePt } from "@/cool";
|
||||
import { computed, ref, watch } from "vue";
|
||||
import type { ClIconProps } from "../cl-icon/props";
|
||||
|
||||
defineOptions({
|
||||
name: "cl-pagination"
|
||||
});
|
||||
|
||||
const props = defineProps({
|
||||
pt: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
},
|
||||
modelValue: {
|
||||
type: Number,
|
||||
default: 1
|
||||
},
|
||||
total: {
|
||||
type: Number,
|
||||
default: 0
|
||||
},
|
||||
size: {
|
||||
type: Number,
|
||||
default: 10
|
||||
}
|
||||
});
|
||||
|
||||
const emit = defineEmits(["update:modelValue", "change"]);
|
||||
|
||||
// 透传样式类型定义
|
||||
type PassThrough = {
|
||||
className?: string;
|
||||
item?: PassThroughProps;
|
||||
itemText?: PassThroughProps;
|
||||
prev?: PassThroughProps;
|
||||
prevIcon?: ClIconProps;
|
||||
next?: PassThroughProps;
|
||||
nextIcon?: ClIconProps;
|
||||
};
|
||||
|
||||
// 解析透传样式配置
|
||||
const pt = computed(() => parsePt<PassThrough>(props.pt));
|
||||
|
||||
// 计算总页数,根据总数和每页大小向上取整
|
||||
const totalPage = computed(() => {
|
||||
if (props.total == 0) return 1;
|
||||
|
||||
return Math.ceil(props.total / props.size);
|
||||
});
|
||||
|
||||
// 绑定值
|
||||
const value = ref(props.modelValue);
|
||||
|
||||
// 计算分页列表,根据当前页码和总页数生成显示的分页按钮
|
||||
const list = computed(() => {
|
||||
const total = totalPage.value;
|
||||
const list: (number | string)[] = [];
|
||||
|
||||
if (total <= 7) {
|
||||
// 总页数小于等于7,显示所有页码
|
||||
for (let i = 1; i <= total; i++) {
|
||||
list.push(i);
|
||||
}
|
||||
} else {
|
||||
// 总是显示第一页
|
||||
list.push(1);
|
||||
|
||||
if (value.value <= 4) {
|
||||
// 当前页在前面: 1 2 3 4 5 ... 100
|
||||
for (let i = 2; i <= 5; i++) {
|
||||
list.push(i);
|
||||
}
|
||||
list.push("...");
|
||||
list.push(total);
|
||||
} else if (value.value >= total - 3) {
|
||||
// 当前页在后面: 1 ... 96 97 98 99 100
|
||||
list.push("...");
|
||||
for (let i = total - 4; i <= total; i++) {
|
||||
list.push(i);
|
||||
}
|
||||
} else {
|
||||
// 当前页在中间: 1 ... 4 5 6 ... 100
|
||||
list.push("...");
|
||||
for (let i = value.value - 1; i <= value.value + 1; i++) {
|
||||
list.push(i);
|
||||
}
|
||||
list.push("...");
|
||||
list.push(total);
|
||||
}
|
||||
}
|
||||
|
||||
return list;
|
||||
});
|
||||
|
||||
// 跳转到指定页面,处理页码点击事件
|
||||
function toPage(item: number | string) {
|
||||
// 忽略省略号点击
|
||||
if (item == "..." || typeof item !== "number") return;
|
||||
|
||||
// 边界检查,确保页码在有效范围内
|
||||
if (typeof item == "number") {
|
||||
if (item > totalPage.value) return;
|
||||
if ((item as number) < 1) return;
|
||||
}
|
||||
|
||||
value.value = item;
|
||||
|
||||
// 触发双向绑定更新和变化事件
|
||||
emit("update:modelValue", item);
|
||||
emit("change", item);
|
||||
}
|
||||
|
||||
// 跳转到上一页
|
||||
function prev() {
|
||||
toPage(value.value - 1);
|
||||
}
|
||||
|
||||
// 跳转到下一页
|
||||
function next() {
|
||||
toPage(value.value + 1);
|
||||
}
|
||||
|
||||
watch(
|
||||
computed(() => props.modelValue),
|
||||
(val: number) => {
|
||||
value.value = val;
|
||||
},
|
||||
{
|
||||
immediate: true
|
||||
}
|
||||
);
|
||||
|
||||
defineExpose({
|
||||
prev,
|
||||
next
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.cl-pagination {
|
||||
@apply flex flex-row justify-center w-full;
|
||||
|
||||
&__prev,
|
||||
&__next,
|
||||
&__item {
|
||||
@apply flex flex-row items-center justify-center bg-surface-100 rounded-lg;
|
||||
height: 60rpx;
|
||||
width: 60rpx;
|
||||
|
||||
&.is-disabled {
|
||||
@apply opacity-50;
|
||||
}
|
||||
|
||||
&.is-dark {
|
||||
@apply bg-surface-700;
|
||||
}
|
||||
}
|
||||
|
||||
&__item {
|
||||
margin: 0 5rpx;
|
||||
|
||||
&.is-active {
|
||||
@apply bg-primary-500;
|
||||
}
|
||||
}
|
||||
|
||||
&__prev {
|
||||
margin-right: 5rpx;
|
||||
}
|
||||
|
||||
&__next {
|
||||
margin-left: 5rpx;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,20 @@
|
||||
import type { PassThroughProps } from "../../types";
|
||||
import type { ClIconProps } from "../cl-icon/props";
|
||||
|
||||
export type ClPaginationPassThrough = {
|
||||
className?: string;
|
||||
item?: PassThroughProps;
|
||||
itemText?: PassThroughProps;
|
||||
prev?: PassThroughProps;
|
||||
prevIcon?: ClIconProps;
|
||||
next?: PassThroughProps;
|
||||
nextIcon?: ClIconProps;
|
||||
};
|
||||
|
||||
export type ClPaginationProps = {
|
||||
className?: string;
|
||||
pt?: ClPaginationPassThrough;
|
||||
modelValue?: number;
|
||||
total?: number;
|
||||
size?: number;
|
||||
};
|
||||
Reference in New Issue
Block a user