:Pagination组件
Posted anyRTC
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了:Pagination组件相关的知识,希望对你有一定的参考价值。
大家好今天的内容是基于vue3实现自己的组件库
系列第二章,本文默认你会安装和创建vue3项目,如果不会请参考vue官网;
Pagination.vue Template
v-select 组件可以先注释掉
v-input 组件可以先注释掉
<div class=v-pagination>
<div v-for=(item, index) in layout :key=index>
<div class=v-pagination-select-box v-if=item === "switch">
<v-select
v-model=activePageSize
:options=pageSizes
:disabled=disabled
@change=handleSizeChange>
</v-select>
</div>
<v-pages
v-if=item === "pages"
ref=cpages
:total=total
:pagerCount=pagerCount
:pageSize=pageSize
v-model=cCurrentPage
:prependText=prependText
:suffixText=suffixText
:hideOnSinglePage=hideOnSinglePage
:disabled=disabled
:background=background
@prev-click=handlePrevClick
@next-click=handleNextClick
></v-pages>
<div :class=["v-pagination-input-box", disabled ] v-if=item === "jump">
<span>前往</span>
<v-input placeholder= :disabled=disabled v-model=jumpValue @input=handleInput @change=handleChange></v-input>
<span>页</span>
</div>
</div>
</div>
Pagination.vue Script
import VairPagination from ../../types/pagination;
import vPages from ./components/Pages;
import vSelect from ../Select/Select;
import vInput from ../Input/Input;
import ref, computed, watchEffect, watch from vue;
export default
name: pagination,
components:
vPages,
vSelect,
vInput
,
props: VairPagination,
setup (props, ctx)
const reg = /^\\+?[1-9][0-9]*$/;
const activePageSize = ref();
const oldJumpValue = ref(props.currentPage);
const jumpValue = ref(props.currentPage);
const cCurrentPage = ref(props.currentPage);
const cpages = ref(null);
const pageSizes = computed(() =>
if (Array.isArray(props.pageSizes))
let arr = [];
props.pageSizes.forEach((item, index) =>
if (!reg.test(item))
throw new Error(page-sizes the item It has to be an integer greater than or equal to 1);
arr.push(
label: `$item条 / 页`,
value: index,
number: item
);
);
return arr;
else
throw new TypeError(`page-sizes wants to receive an array, but received a $typeof props.pageSizes`);
);
const handleSizeChange = (option) =>
ctx.emit(size-change, option.number);
;
const handlePrevClick = (index) =>
ctx.emit(prev-click, index);
setJumpValue();
;
const handleNextClick = (index) =>
ctx.emit(next-click, index);
setJumpValue();
;
const handleInput = (value) =>
if (!reg.test(value) && value !== )
jumpValue.value = oldJumpValue.value;
else
oldJumpValue.value = value;
;
const handleChange = (value) =>
const max = Math.ceil(props.total / props.pageSize);
if (value < 1)
jumpValue.value = 1;
oldJumpValue.value = 1;
else if (value > max)
jumpValue.value = max;
oldJumpValue.value = max;
cCurrentPage.value = +jumpValue.value;
;
const setJumpValue = () =>
jumpValue.value = cCurrentPage.value;
oldJumpValue.value = cCurrentPage.value;
;
watchEffect(() =>
activePageSize.value = pageSizes.value[0].label;
);
watchEffect(() =>
if (!reg.test(props.pagerCount) || props.pagerCount < 7 || props.pagerCount > 21)
throw new TypeError(`pager-count value of can only be an integer greater than or equal to 7 and less than or equal to 21, but received a $props.pagerCount`);
);
watchEffect(() =>
if (!reg.test(props.pageSize))
throw new Error(pager-size It has to be an integer greater than or equal to 1);
);
watch(() => props.pageSize, () =>
setJumpValue();
);
watchEffect(() =>
if (!reg.test(props.currentPage))
throw new Error(current-page It has to be an integer greater than or equal to 1);
else
cCurrentPage.value = props.currentPage;
);
watchEffect(() =>
if (typeof props.total !== number || props.total < 0)
throw new Error(total must be a number greater than or equal to 0);
);
watchEffect(() =>
ctx.emit(current-change, cCurrentPage.value);
setJumpValue();
);
return
handleSizeChange,
handlePrevClick,
handleNextClick,
handleInput,
handleChange,
pageSizes,
activePageSize,
jumpValue,
cCurrentPage,
cpages
Pagination.vue Props
const VairPagination =
background: // 是否开启背景色
type: Boolean,
default: () =>
return false;
,
pageSize: // 每页显示几条数据
type: Number,
default: () =>
return 10;
,
total: // 数据总数量
type: Number,
default: () =>
return 0;
,
pagerCount: // 当总页数超过该值时会开启折叠 最低为 7
type: Number,
default: () =>
return 7;
,
pageSizes: // 每页显示个数选择器的选项
type: Array,
default: () =>
return [10, 20, 30, 40, 50, 100];
,
prependText: // 后退按钮文字
type: String,
default: () =>
return ;
,
suffixText: // 前进按钮文字
type: String,
default: () =>
return ;
,
disabled: // 是否禁用
type: Boolean,
default: () =>
return false;
,
hideOnSinglePage: // 只有一页时是否隐藏
type: Boolean,
default: () =>
return false;
,
currentPage: // 当前页数
type: Number,
default: () =>
return 1;
,
layout: // 组件布局显示顺序
type: Array,
default: () =>
return [switch, pages, jump];
,
;
// Event
// size-change (number)
// current-change (index)
// prev-click (index)
// next-click (index)
export default VairPagination;
Pagination.vue Style
<style lang=less scoped>
.v-pagination
display: flex;
align-items: center;
.v-pagination-select-box, .v-pagination-input-box
width: 120px;
/deep/.v-select, /deep/.v-input
min-width: 0;
/deep/.v-input
height: 30px;
.v-input-box, .input
height: 30px;
.suffix
height: 25px;
.v-pagination-input-box
display: flex;
align-items: center;
width: 120px;
/deep/.v-input
width: 50px;
margin: 0 6px;
.input
text-indent: 0px;
text-align: center;
span
font-size: 14px;
.disabled
cursor: not-allowed;
span
color: #c0c4cc;
</style>
Pages.vue Template
<div class=v-pages ref=cPages>
<div :class=["prepend", prependDisabled , disabled ]
ref=prepend
@click=handlePrependClick>
<p v-if=prependText> prependText </p>
<i v-if=!prependText class=iconfont icon-zuojiantou></i>
</div>
<ul class=v-pages-ul>
<li :class=["v-pages-li", activeLi: modelValue === item , disabled ]
:ref=el => if (el) liList[index] = el
v-for=(item, index) in calculatePagesButtonList :key=index
@click=handlePagesLiClick(item)>
<span :class=[ color: !background ] v-if=item !== "suffix" && item !== "prepend"> item </span>
<i @mouseenter=handleMouseEnter(item)
@mouseleave=handleMouseLeave(item)
@click=handleIClick(item)
v-else
:class=["iconfont", "icon-ellipsis2",
"icon-chevronsrightshuangyoujiantou": doubleRight && item === "suffix" ,
"icon-chevronsleftshuangzuojiantou": doubleLeft && item === "prepend" ]>
</i>
</li>
</ul>
<div
ref=suffix
:class=["suffix", suffixDisabled , disabled ]
@click=handleSuffixClick>
<p v-if=suffixText> suffixText </p>
<i v-if=!suffixText class=iconfont icon-youjiantou></i>
</div>
</div>
Pages.vue Script
import ref, computed, watchEffect, onMounted from vue;
export default
name: pages,
props:
total: Number,
pagerCount: Number,
pageSize: Number,
prependText: String,
suffixText: String,
disabled: Boolean,
hideOnSinglePage: Boolean,
background: Boolean || String,
modelValue: Number
,
setup (props, ctx)
const medianButtonList = ref([]);
const prependDisabled = ref(true);
const suffixDisabled = ref(true);
const doubleLeft = ref(false);
const doubleRight = ref(false);
const liList = ref([]);
const prepend = ref(null);
const suffix = ref(null);
const cPages = ref(null);
onMounted(() =>
watchEffect(() =>
liList.value.forEach(item =>
!props.background && (item.style.backgroundColor = transparent);
);
!props.background && (prepend.value.style.backgroundColor = transparent);
!props.background && (suffix.value.style.backgroundColor = transparent);
);
watchEffect(() =>
if (calculatePagesButtonList.value.length <= 1 && props.hideOnSinglePage)
cPages.value.style.display = none;
else
cPages.value.style.display = flex;
);
);
const handlePagesLiClick = (index) =>
if (props.disabled) return
if (typeof index === number && props.modelValue !== index)
ctx.emit(update:modelValue, index);
ctx.emit(current-change, index);
;
const handleMouseEnter = (item) =>
if (props.disabled) return
if (item === prepend)
doubleLeft.value = true;
else if (item === suffix)
doubleRight.value = true;
;
const handleMouseLeave = (item) =>
if (props.disabled) return
if (item === prepend)
doubleLeft.value = false;
else if (item === suffix)
doubleRight.value = false;
;
const handleIClick = (item) =>
if (props.disabled) return
if (item === prepend)
const num = props.modelValue - 3;
ctx.emit(update:modelValue, num < 1? 1 : num);
else if (item === suffix)
const maxPages = Math.ceil(props.total / props.pageSize);
const num = props.modelValue + 3;
ctx.emit(update:modelValue, num > maxPages? maxPages : num);
ctx.emit(current-change, props.modelValue);
;
const handlePrependClick = () =>
if (props.disabled) return
if (props.modelValue <= 1) return;
ctx.emit(update:modelValue, props.modelValue - 1);
ctx.emit(prev-click, props.modelValue);
;
const handleSuffixClick = () =>
if (props.disabled) return
const value = calculatePagesButtonList.value;
const item = value[value.length - 1];
if (props.modelValue >= item) return;
ctx.emit(update:modelValue, props.modelValue + 1);
ctx.emit(next-click, props.modelValue);
;
const calculatePagesButtonList = computed(() =>
const value = props.modelValue;
const maxPages = Math.ceil(props.total / props.pageSize);
const bool = (maxPages - props.pagerCount) > 0;
const maxCurrentPage = (value - maxPages) > 0? maxPages : value;
const pagerCountHalf = Math.ceil((props.pagerCount - 2) / 2);
const a = (maxCurrentPage + pagerCountHalf) < maxPages;
const b = (maxCurrentPage - pagerCountHalf) <= 2;
let pagesButtonList = [];
if (bool)
if (b)
for(let i = 1; i < props.pagerCount; i++)
pagesButtonList.push(i);
pagesButtonList.push(suffix);
pagesButtonList.push(maxPages);
else if (a)
pagesButtonList.push(1);
pagesButtonList.push(prepend);
for(let i = (maxCurrentPage - pagerCountHalf + 1); i < (maxCurrentPage + pagerCountHalf); i++)
pagesButtonList.push(i);
pagesButtonList.push(suffix);
pagesButtonList.push(maxPages);
else if (!a)
pagesButtonList.push(1);
pagesButtonList.push(prepend);
for(let i = (maxPages - props.pagerCount + 2); i <= maxPages; i++)
pagesButtonList.push(i);
else
for (let i = 1; i <= maxPages; i++)
pagesButtonList.push(i);
return pagesButtonList;
);
const calculateCurrentPage = () =>
const value = calculatePagesButtonList.value;
const item = value[value.length - 1];
ctx.emit(update:modelValue, props.modelValue > item? item : props.modelValue);
;
watchEffect(() =>
calculateCurrentPage();
);
watchEffect(() =>
const value = calculatePagesButtonList.value;
const item = value[value.length - 1];
prependDisabled.value = props.modelValue === 1;
suffixDisabled.value = props.modelValue >= item;
);
return
calculatePagesButtonList,
medianButtonList,
prependDisabled,
suffixDisabled,
handlePagesLiClick,
handlePrependClick,
handleSuffixClick,
handleMouseEnter,
handleMouseLeave,
handleIClick,
doubleRight,
doubleLeft,
liList,
prepend,
cPages,
suffix
Pages.vue Style
<style lang=less scoped>
.v-pages
display: flex;
align-items: center;
margin: 0 14px;
.prepend, .suffix
display: flex;
align-items: center;
justify-content: center;
min-width: 30px;
min-height: 28px;
box-sizing: border-box;
padding: 0 6px;
margin: 0 5px;
background-color:#F4F4F5;
cursor: pointer;
p, i
font-size: 12px;
color: #333;
font-weight: 600;
&:hover
p, i
color: #409EFF;
.prependDisabled, .suffixDisabled
p, i
color: #CDC9CC !important;
cursor: not-allowed;
.v-pages-ul
display: flex;
align-items: center;
.v-pages-li
margin: 0 5px;
background-color:#F4F4F5;
cursor: pointer;
span, i
display: block;
min-width: 30px;
box-sizing: border-box;
padding: 0 6px;
line-height: 28px;
text-align: center;
font-size: 12px;
color: #333;
font-weight: 600;
&:hover
span, i
color: #409EFF;
.activeLi
background-color:#409EFF;
span
color: #fff;
.color
color: #409EFF !important;
&:hover
span
color: #fff;
.disabled
p, i, span
color: #c0c4cc !important;
cursor: not-allowed !important;
</style>
index.js 出口文件中引入组件
// Pagination 分页
import Pagination from ./components/Pagination/Pagination.vue;
import Pages from ./components/Pagination/components/Pages.vue;
const Vair = function(Vue)
Vue.component(`v-$Pagination.name`, Pagination);
Vue.component(`v-$Pages.name`, Pages);
export default Vair;
使用组件
在main.js中引入
import createApp from vue;
import App from ./App.vue;
import Vair from ./libs/vair/index.js;
const app = createApp(App);
app.use(Vair).mount(#app);
App.vue中调用
<template>
<div>
<v-pagination
:page-sizes=pageSizes
:pager-count=pagerCount
:total=total
:page-size=pageSize
:current-page=currentPage
:background=background
:hideOnSinglePage=false
:disabled=disabled
@current-change=handleCurrentChange
@prev-click=handlePrevClick
@next-click=handleNextClick
@size-change=handleSizeChange
></v-pagination>
</div>
</template>
<script>
import ref from vue;
export default
setup ()
const pageSizes = ref([10, 20, 30, 40, 50, 100]);
const pageSize = ref(10);
const total = ref(50500);
const currentPage = ref(10);
const pagerCount = ref(7);
const background = ref(true);
const prependText = ref(prepre);
const suffixText = ref(nextnext);
const disabled = ref(false);
const handleCurrentChange = (index) =>
console.log(index)
;
const handlePrevClick = (index) =>
console.log(handlePrevClick 触发了, index);
;
const handleNextClick = (index) =>
console.log(handleNextClick 触发了, index);
;
const handleSizeChange = (number) =>
pageSize.value = number;
;
return
pageSizes,
pageSize,
total,
disabled,
currentPage,
pagerCount,
handleCurrentChange,
handlePrevClick,
handleNextClick,
handleSizeChange,
background,
prependText,
suffixText
</script>
<style lang=less scoped>
div
margin-top: 20px;
</style>
效果展示
以上是关于:Pagination组件的主要内容,如果未能解决你的问题,请参考以下文章
AngularJs的UI组件ui-Bootstrap分享——Pager和Pagination
Element Pagination 分页修改页码当前页无效