: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 分页修改页码当前页无效