组件封装练习2---分页器

技术栈

vue3、ts、less

封装代码

<template>
    <div class="paging">
        <div>
            <p>共 <span>{{ total }}</span> 条</p>
            <select @change="sizeChange">
                <option :value="5">每条5页</option>
                <option :value="10">每条10页</option>
                <option :value="15">每条15页</option>
                <option :value="20">每条20页</option>
                <option :value="100">每条100页</option>
            </select>
            <div class="down_up">
                <img src="./../assets/images/left2.png" @click="jump_to(1)">
                <img src="./../assets/images/left.png" @click="jump_to(2)">
                <template v-if="(maxPage as number) <= 8">
                    <div v-for="item in maxPage" :class="{ 'active': current == item }" @click="pointPage(item)">
                        {{ item }}
                    </div>
                </template>
                <template v-else>
                    <div :class="{ 'active': current == 1 }" @click="pointPage(1)">
                        {{ 1 }}
                    </div>
                    <template v-if="current as number < 5">
                        <div v-for="item in 4" :class="{ 'active': current == item + 1 }" @click="pointPage(item + 1)">
                            {{ item + 1 }}
                        </div>
                        <div>
                            ...
                        </div>
                    </template>
                    <template v-else-if="(Number(maxPage) as any - (current as number)) < 4">
                        <div>
                            ...
                        </div>
                        <div v-for="item in 4" :class="{ 'active': current == Number(maxPage) as number - 5 + item }"
                            @click="pointPage(Number(maxPage) as number - 5 + item)">
                            {{ Number(maxPage) as number - 5 + item }}
                        </div>
                    </template>
                    <template v-else>
                        <div>
                            ...
                        </div>
                        <div v-for="item in 3" :class="{ 'active': current == Number(current) - 2 + item }"
                            @click="pointPage(Number(current) - 2 + item)">
                            {{ Number(current) as number - 2 + item }}
                        </div>
                        <div>
                            ...
                        </div>
                    </template>
                    <div :class="{ 'active': current == maxPage }" @click="pointPage(maxPage)">
                        {{ maxPage }}
                    </div>
                </template>
                <img src="./../assets/images/right.png" @click="jump_to(3)">
                <img src="./../assets/images/right2.png" @click="jump_to(4)">
            </div>
            <div class="go_to">
                跳至
                <a-input @blur="inputChange" placeholder="1" :value="current"></a-input>
                页
            </div>
        </div>
    </div>
</template>

<script lang='ts' setup>
import { ref, watch, onMounted } from 'vue'
import { message } from 'ant-design-vue';

onMounted(() => {

})

message.config({
    maxCount: 3,
});


const father = defineProps<{
    total: number | undefined,
    current: number | string,
    size: number | string,
}>()

const fatherFn = defineEmits(["changePagingData", "update:current", "update:size"])

const trigger = function () {
    fatherFn("changePagingData", {
        size: father.size,
        current: father.current
    })
}


const bigPageFn = function (): number {
    let num: any = 0;
    (num as any) = parseInt(num + (father.total as any) / (father.size as any));
    ((father.total as any) % (father.size as any)) == 0 ? num : ++num
    return num
}

let maxPage = ref<number>(bigPageFn())
watch(
    () => [father.size, father.current, father.total],
    (newvalue, oldvalue) => {



        if (newvalue[0] != (oldvalue as any)[0]) {
            (maxPage.value as any) = bigPageFn();
            // father.current = 1;
            fatherFn("update:current", 1)
        }


        if (newvalue[2] != (oldvalue as any)[2]) {

            (maxPage.value as any) = bigPageFn();
            fatherFn("update:current", 1)

        }
    },
    {
        deep: true,
    }
)


const jump_to = function (num: number): void {
    switch (num) {
        case 1:
            fatherFn("update:current", 1);
            trigger()
            return;

        case 2:
            if (father.current as number > 1) {
                fatherFn("update:current", father.current as any - 1)
                // father.current = father.current as any - 1
            } else {
                message.warning("已经是第一页了")
            }
            trigger()
            return;

        case 3:

            if ((father.current as number) < (maxPage.value as number)) {
                // father.current = father.current as any + 1
                fatherFn("update:current", father.current as any + 1)

            } else {
                message.warning("已经是最后一页了")
            }
            trigger()
            return;

        case 4:
            // father.current = maxPage.value as number

            fatherFn("update:current", maxPage.value)
            trigger()
            return;

    }
}


const inputChange = function (e: any) {


    if (e.target.value > maxPage.value) {
        message.warning("请输入正确页数")
        return;
    }
    fatherFn("update:current", e.target.value)

    // father.current = e.target.value
    trigger()
}


const pointPage = function (num: number) {
    // father.current = num
    fatherFn("update:current", num)
    trigger()
}


const sizeChange = function (e: any) {
    fatherFn("update:size", e.target.value)
    trigger()
}
</script>

<style scoped lang="less">
.paging {
    width: 100%;
    height: 80px;

    display: flex;
    justify-content: center;
    align-items: center;

    >div {
        display: flex;
        justify-content: center;
        align-items: center;

        height: 32px;
        width: auto;

        p {
            height: 32px;
            line-height: 32px;
            margin: 0;
        }

        select {
            height: 32px;
            margin: 0 16px;
        }

        .down_up {
            display: flex;

            img {
                width: 32px;
                margin-left: 16px;
                cursor: pointer;

            }

            >div {
                width: 32px;
                height: 32px;
                cursor: pointer;
                background-color: RGBA(244, 244, 244, 1);

                text-align: center;
                line-height: 32px;
                font-size: 14px;

                margin-left: 16px;
            }

            .active {
                background-color: rgba(13, 152, 162, 1);
                color: #fff;
            }
        }

        .go_to {
            display: flex;
            height: 32px;
            line-height: 32px;
            margin-left: 16px;

            .ant-input {
                width: 80px;
                height: 32px;

                margin: 0 16px;
            }
        }
    }
}
</style>

组件使用

<template>
    <Paging :total="total" v-model:current="current" v-model:size="size" @changePagingData="changePagingData"></Paging>
</template>

<script setup lang="ts">
    import Paging from "路径"
    import {ref} from "vue"

    interface PageType{
        current:number | stirng;
        size:number | stirng;
    }

    const total = ref<number>(50)
    const currentPage = ref<PageType>({
        current:1,
        size:5
    })

    const changePagingData = function(val:PageType){
        console.log(val);//组件返回的当前页和每页数
    }
</script>

解析

1.首先是父子传参:需要一个total(数据有多少条)和一个函数changePaginData(父组件函数,切换页码时需要传给父组件),利用v-model中update函数实现父子current和size的联动。拿到total我们需要先根据size(每页渲染的数量)计算出总共的页码数量

2.定义一个函数,每次页码变化或者每页数据数量变化,都会触发父组件函数,并将current和size传给父组件。

3.向左向右的按钮,一共有四个,向左和直接到第一页,向右和直接到最后,这个比较简单,往前时,只需要判断是否是第一页,往后时,只需要判断是否是最后一页即可

4.点击页码跳转和输入页码跳转,这两个也比较简单,注意:输入页码跳转对值可能需要判断输入值是否在1到最大页码数之间。这里我写的是输入框失焦跳转,自己喜欢什么样可以自己改一下,用按钮也行

5.渲染html,这一环可以根据自己的喜好渲染,但是需要设置好参数,不然会出错,我的参数如上代码备注

6.最后就是写watch事件,watch中主要监听的参数有current,size,total这三个参数,其中最重要的就是size和total,因为size的改变可能会改变最大页码数,total的改变也同样会。我这里处理size带来的改变是让current直接变为1,也就是直接跳回第一页。而total改变,比如现在一共三页,我们删除最后一条数据后,应该回到第二页,我就是做了一个这个处理。注意,这两个参数都可能会改变最大页码数,所以一定要进行计算,否则会出问题。

总结

这个组件总的来说还是比较简单,但是需要注意很多细节,无论是html渲染和js都需要考虑到一定的细节,才会保证尽量不会出错。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值