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

Element-ui组件--pagination分页的使用

Element-ui(el-tableel-pagination)实现表格分页

vue实现分页组件

jquery pagination分页 页码显示出来的原理