【前端项目——分页器】手写分页器实现(JS / React)

news2024/11/19 22:37:14

组件介绍

用了两种方式实现,注释详细~
可能代码写的不够简洁,见谅🙁
在这里插入图片描述
1. 包含内容显示的分页器
网上看了很多实现,很多只有分页器部分,没和内容显示联动。
因此我增加了模拟content的显示,这里模拟了32条数据,通过分页器控制每页的显示。
2. 切换每页显示数目
列举了三种,5,10,20条每页
在这里插入图片描述

3. 输入值后通过enter跳转
做了一个范围保护,如果超出当前范围,会自动变成最大或最小的页码。(做提示也可以,但我不想点提示的确认)
在这里插入图片描述

原生JS实现

1. HTML

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <link rel="stylesheet" href="style.css">
</head>

<body>
    <div class="content">
    </div>
    <div class="page">
        <button class="prev disabled">&lt;&lt;</button>
        <button class="prev disabled">&lt;</button>

        <ul class="page-list">
        </ul>

        <button class="next">&gt;</button>
        <button class="next">&gt;&gt;</button>

        <select class="page-size">
            <option value="5">每页显示5条</option>
            <option value="10">每页显示10条</option>
            <option value="20">每页显示20条</option>
        </select>

        <span>跳转到</span>
        <input class="jump-to" type="number" value="1">
        <span></span>
    </div>
    <script src="script.js"></script>
</body>

</html>

2.CSS

* {
    font-size: 16px;
    margin: 0;
    padding: 0;
}

a {
    display: inline-block;
    text-decoration: none;
    color: #000;
    padding: 10px 15px;
}

.content {
    display: flex;
    flex-direction: row;
    align-items: center;
    flex-wrap: wrap;
    padding: 20px;
}

.content div {
    width: 220px;
    height: 50px;
    background-color: #78b5e7;
    margin: 10px;
}

.page {
    display: flex;
    justify-content: center;
    align-items: center;
    gap: 10px;
    width: 100%;
    height: 100px;
    background-color: #f5f5f5;
}

.page-list {
    list-style: none;
    display: flex;
    flex-direction: row;
}

.prev,
.next,
.page-num {
    border-radius: 4px;
    padding: 0;
    border: 0;
    cursor: pointer;
}

.prev,
.next {
    padding: 10px 15px;
}

.prev:hover,
.next:hover,
.page-num:hover {
    background-color: #e9e7e7;
}

.active {
    background-color: #bee5fc;
}

select {
    font-size: 16px;
    padding: 5px 5px;
    border-radius: 4px;
    border: 1px solid #ccc;
}

.jump-to {
    font-size: 16px;
    padding: 5px 5px;
    border-radius: 4px;
    width: 35px;
    border: 1px solid #ccc;
}

button:active {
    background-color: #fff;
}

.disabled {
    color: #b3b3b3;
    cursor: not-allowed;
    opacity: 0.6;
}

3. JS

let content = document.querySelector('.content');
let contentNum = 32;
for (let i = 0; i < contentNum; i++) {
    let div = document.createElement('div');
    div.innerHTML = i + 1;
    content.appendChild(div);
}

let current = 1; //当前页码,默认是第一页

let pagelist = document.querySelector('.page-list');

let showpage = document.querySelector('.page-size');
let pagenum = showpage.value; //默认一页显示多少内容
let num = Math.ceil(contentNum / parseInt(pagenum)); //默认显示的页数的页数

let prev = document.querySelectorAll('.prev');
let next = document.querySelectorAll('.next');


// 展示当前页码的内容
function showContent() {
    let start = (current - 1) * parseInt(pagenum);
    let end = start + parseInt(pagenum);
    for (let i = 0; i < content.children.length; i++) {
        if (i >= start && i < end) {
            content.children[i].style.display = 'block';
        } else {
            content.children[i].style.display = 'none';
        }
    }
}
// 展示页码列表
function showPage() {
    // 清空原有的超出所需页面数量的页码列表 
    while (pagelist.children.length > num) {
        pagelist.removeChild(pagelist.children[num]);
    }
    // 补充所需页面数量的页码列表
    for (let i = pagelist.children.length; i < num; i++) {
        let li = document.createElement('li');
        let a = document.createElement('a');
        a.href = '#' + i;
        a.innerHTML = i + 1;
        li.appendChild(a);
        li.classList.add('page-num');
        // 高亮默认页码
        if (i === 0) {
            li.classList.add('active');
        }
        pagelist.appendChild(li);
    }
    // 找到要点击的目标元素
    let targetElement = pagelist.querySelector('li:nth-child(1) a');
    // 使用click()方法触发点击事件
    targetElement.click();
    //显示当前页码的内容
    showContent();
}
// 按钮状态
function buttonStatus() {
    // 两个按钮都要取消禁用
    prev.forEach(function (item) {
        item.classList.remove('disabled');
    });
    next.forEach(function (item) {
        item.classList.remove('disabled');
    });
    // 如果当前页码是第一页,那么上一页和首页按钮都要禁用
    if (current == 1) {
        prev[0].classList.add('disabled');
        prev[1].classList.add('disabled');
    }
    // 如果当前页码是最后一页,那么下一页和末页按钮都要禁用
    else if (current == num) {
        next[0].classList.add('disabled');
        next[1].classList.add('disabled');
    }
}
//默认显示最开始的内容
showPage();

// 绑定事件

//select改变
showpage.addEventListener('change', function () {
    // 重新计算页数
    pagenum = showpage.value;
    num = Math.ceil(contentNum / parseInt(pagenum));
    // 超出范围的页码要置为最后一页,否则会报错
    if (current > num) {
        current = num;
    }
    // 显示当前页码的内容
    showPage();
});
//点击页码列表
pagelist.addEventListener('click', function (event) {
    // 点击的是页码列表
    if (event.target.tagName === 'A') {
        // 取消当前页码的active
        pagelist.children[current - 1].classList.remove('active');
        // 点击的页码会变成active
        event.target.parentNode.classList.add('active');
        // 更新当前页码
        current = event.target.innerHTML;
        // 显示当前页码的内容
        buttonStatus();
        showContent();
    }
}
);
//绑定按钮事件
//如果当前大于1,那么两个prev都不禁用
//如果当前在最后一页,此时下一页禁用,那么点击后要取消下一页的禁用
for (let i = 0; i < prev.length; i++) {
    prev[i].addEventListener('click', function () {
        if (current > 1) {
            //取消当前页码的active
            pagelist.children[current - 1].classList.remove('active');
            //如果当前页码是最后一页,那么下一页要取消禁用
            next.forEach(function (item) {
                item.classList.remove('disabled');
            });
            if (i == 0)
                //如果是第一个prev,回到第一页
                current = 1;
            else
                //回到上一页
                current--;
            //添加active到当前页码
            pagelist.children[current - 1].classList.add('active');
            //如果当前页码是第一页,那么上一页要取消禁用
            if (current === 1) {
                prev.forEach(function (item) {
                    item.classList.add('disabled');
                });
            }
        }
        showContent();
    }
    )
}
//点击下一页
for (let i = 0; i < next.length; i++) {
    next[i].addEventListener('click', function () {
        if (current < num) {
            //取消当前页码的active
            pagelist.children[current - 1].classList.remove('active');
            //如果当前页码是第一页,那么上一页要取消禁用
            prev.forEach(function (item) {
                item.classList.remove('disabled');
            });
            //回到最后一页
            if (i == 1)
                current = num;
            else
                current++;
            //添加active到当前页码
            pagelist.children[current - 1].classList.add('active');
            //如果当前页码是最后一页,那么下一页要取消禁用
            if (current === num) {
                next.forEach(function (item) {
                    item.classList.add('disabled');
                })
            }
        }
        showContent();
    }
    )
}

//跳转到指定页码
let jump = document.querySelector('.jump-to');
jump.addEventListener('keydown', function (event) {
    if (event.keyCode === 13) {
        // 溢出保护
        if (event.target.value > pagelist.children.length) {
            event.target.value = pagelist.children.length;
        }
        if (event.target.value < 1) {
            event.target.value = 1;
        }
        // 模拟点击事件
        let targetElement = pagelist.querySelector('li:nth-child(' + event.target.value + ') a');
        // 使用click()方法触发点击事件
        targetElement.click();
        buttonStatus();
        showContent();
    }
});


React实现

还是react方便。。。。😟
在这里插入图片描述

1.jsx

import React, { useEffect, useState } from 'react'
import styles from './App.module.css'

export default function App() {
    //创建大小为32的数组,内容为索引+1
    const content = Array.from({ length: 32 }, (_, i) => i + 1);

    const [currentPage, setCurrentPage] = useState([]);//当前页内容
    const [current, setCurrent] = useState(1);//当前页码
    const [pagenum, setPagenum] = useState(5);//每页显示条数
    const num = Math.ceil(content.length / pagenum);//总页数

    const [previousDisabled, setPreviousDisabled] = useState(true);//上一页按钮是否禁用
    const [nextDisabled, setNextDisabled] = useState(false);//下一页按钮是否禁用

    const [inputValue, setInputValue] = useState('');//跳转页码输入框值

    function showContent() {//显示当前页内容
        let start = (current - 1) * pagenum;
        let end = start + pagenum;
        setCurrentPage(content.slice(start, end));
    }
    function buttonStatus() {//按钮状态
        if (current == 1) {//第一页
            setPreviousDisabled(true);
            setNextDisabled(false);
        }
        if (current == num) {//最后一页
            setNextDisabled(true);
            setPreviousDisabled(false);
        }
        if (current != 1 && current != num) {//中间页
            setPreviousDisabled(false);
            setNextDisabled(false);
        }
    }

    useEffect(() => {//页面初始化
        showContent();
        buttonStatus();
    }, [current, pagenum]);

    return (
        <div style={{ padding: '20px' }}>
            <div className={styles.content}>
                {
                    // 创建模拟数据内容
                    currentPage.map((item, index) => (
                        <div key={index}>{item}</div>
                    ))
                }
            </div>
            <div className={styles.page}>
                {/*  向前按钮 */}
                <button className={`${styles.prev} ${previousDisabled ? styles.disabled : ''}`}
                    onClick={() => { setCurrent(1) }}
                >&lt;&lt;</button>
                <button className={`${styles.prev} ${previousDisabled ? styles.disabled : ''}`}
                    onClick={() => { current > 1 ? setCurrent(current - 1) : null }}
                >&lt;</button>
                {/*  页码 */}
                <ul className={styles.pageList}>
                    {
                        Array.from({ length: num }, (_, i) => i + 1).map(item => (
                            <li key={item}
                                className={current === item ? styles.active : ''}
                                onClick={() => {
                                    setCurrent(item);
                                }}>
                                <a href={`#${item}`}>{item}</a>
                            </li>
                        ))
                    }
                </ul>
                {/* 向后按钮 */}
                <button className={`${styles.next} ${nextDisabled ? styles.disabled : ''}`}
                    onClick={() => { current < num ? setCurrent(current + 1) : null }}
                >&gt;</button>
                <button className={`${styles.next} ${nextDisabled ? styles.disabled : ''}`}
                    onClick={() => { setCurrent(num) }}
                >&gt;&gt;</button>
                {/* 页面数量选择框 */}
                <select className={styles.pageSize} onChange={(e) => {
                    setPagenum(parseInt(e.target.value));
                    setCurrent(1);
                    setInputValue(1);
                }}>
                    <option value="5">每页显示5</option>
                    <option value="10">每页显示10</option>
                    <option value="20">每页显示20</option>
                </select>
                {/* 跳转页面输入框 */}
                <span>跳转到</span>
                <input className={styles.jumpTo} type="number" defaultValue={inputValue} value={inputValue}
                    //记录输入框值
                    onChange={(e) => {
                        setInputValue(e.target.value);
                    }}
                    //跳转到指定页码,回车键触发,限制输入范围
                    onKeyDown={(e) => {
                        if (e.key === 'Enter') {//回车键触发
                            let value = parseInt(e.target.value);
                            if (value > num) value = num;//限制输入范围
                            if (value < 1) value = 1;
                            setCurrent(value);//指定页码
                            setInputValue(value);//更新输入框(因为限制输入范围)
                        }
                    }} />
                <span></span>
            </div>
        </div>
    )
}

2. CSS

* {
    font-size: 16px;
    margin: 0;
    padding: 0;
}

a {
    display: inline-block;
    text-decoration: none;
    color: #000;
    padding: 10px 15px;
}

.content {
    display: flex;
    flex-direction: row;
    align-items: center;
    flex-wrap: wrap;
    padding: 20px;
}

.content div {
    width: 220px;
    height: 50px;
    background-color: #78b5e7;
    margin: 10px;
}

.page {
    display: flex;
    justify-content: center;
    align-items: center;
    gap: 10px;
    width: 100%;
    height: 100px;
    background-color: #f5f5f5;
}

.page-list {
    list-style: none;
    display: flex;
    flex-direction: row;
}

.prev,
.next,
.page-num {
    border-radius: 4px;
    padding: 0;
    border: 0;
    cursor: pointer;
}

.prev,
.next {
    padding: 10px 15px;
}

.prev:hover,
.next:hover,
.page-num:hover {
    background-color: #e9e7e7;
}

.active {
    background-color: #bee5fc;
}

select {
    font-size: 16px;
    padding: 5px 5px;
    border-radius: 4px;
    border: 1px solid #ccc;
}

.jump-to {
    font-size: 16px;
    padding: 5px 5px;
    border-radius: 4px;
    width: 35px;
    border: 1px solid #ccc;
}

button:active {
    background-color: #fff;
}

.disabled {
    color: #b3b3b3;
    cursor: not-allowed;
    opacity: 0.6;
}
小记

写原生js的时候还是比较慢,后续要加强

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1642064.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

JavaEE初阶Day 15:文件IO(1)

目录 Day 15&#xff1a;文件IO&#xff08;1&#xff09;IO文件1. 路径2. 文件的分类3. 使用Java针对文件系统进行操作3.1 属性3.2 构造方法3.3 方法 Day 15&#xff1a;文件IO&#xff08;1&#xff09; IO I&#xff1a;Input输入 O&#xff1a;Output输出 输入输出规则…

使用机器学习确定文本的编程语言

导入必要的库 norman Python 语句&#xff1a;import <span style"color:#000000"><span style"background-color:#fbedbb"><span style"color:#0000ff">import</span> pandas <span style"color:#0000ff&quo…

onedrive下載zip檔案有20G限制,如何解決

一般來說&#xff0c;OneDrive網頁版對文件下載大小的限制如下圖所示&#xff0c;更多資訊&#xff0c;請您參考這篇文章&#xff1a;OneDrive 和 SharePoint 中的限制 - Microsoft Support 因此我們推薦您使用OneDrive同步用戶端來同步到本地電腦&#xff0c;您也可以選擇只同…

【实验】使用docker-compose编排lnmp(dockerfile) 完成Wordpress 部署

环境准备 docker&#xff1a;192.168.67.30 虚拟机&#xff1a;4核4G 关闭防火墙 systemctl stop firewalld systemctl disable firewalld setenforce 0 安装docker 直接点击【复制】粘贴到xshell中即可&#xff0c; 执行过程中若出现睡眠(sleep)通过 kill -9 pid号 &#x…

库存管理系统开源啦

软件介绍 ModernWMS是一个针对小型物流仓储供应链流程的开源库存管理系统。该系统的开发初衷是为了满足中小型企业在有限IT预算下对仓储管理的需求。通过总结多年ERP系统研发经验&#xff0c;项目团队开发了这套适用于中小型企业的系统&#xff0c;以帮助那些有特定需求的用户。…

vector的使用

1.构造函数 void test_vector1() {vector<int> v; //无参的构造函数vector<int> v2(10, 0);//n个value构造&#xff0c;初始化为10个0vector<int> v3(v2.begin(), v2.end());//迭代器区间初始化,可以用其他容器的区间初始化vector<int> v4(v3); //拷贝…

【 书生·浦语大模型实战营】作业(六):Lagent AgentLego 智能体应用搭建

【 书生浦语大模型实战营】作业&#xff08;六&#xff09;&#xff1a;Lagent & AgentLego 智能体应用搭建 &#x1f389;AI学习星球推荐&#xff1a; GoAI的学习社区 知识星球是一个致力于提供《机器学习 | 深度学习 | CV | NLP | 大模型 | 多模态 | AIGC 》各个最新AI方…

jupyter notebook 设置密码报错ModuleNotFoundError: No module named ‘notebook.auth‘

jupyter notebook 设置密码报错ModuleNotFoundError: No module named ‘notebook.auth‘ 原因是notebook新版本没有notebook.auth 直接输入以下命令即可设置密码 jupyter notebook password

链表的带环问题 链表的深度拷贝

1.1. 链表是否带环 代码很简单&#xff0c;最主要就是如何证明 首先判断链表是否带环&#xff0c;可以定义两个指针&#xff0c;一个快指针一个慢指针。快指针走两步&#xff0c;慢指针走一步一定会相遇吗&#xff1f;有没有可能会超过&#xff1f;假设进环的时候fast和slow的…

87、动态规划-最长地址子序列

思路&#xff1a; 使用递归来理解题目&#xff0c;然后在看如何优化&#xff0c;假设我当前使用元素那么最长是多少&#xff0c;如果不使用当前元素最长是多少&#xff0c;然后取最大值。 代码如下&#xff1a; //算出最长递增子序列的长度public static int lengthOfLIS02(…

【机器学习】集成方法---Boosting之AdaBoost

一、Boosting的介绍 1.1 集成学习的概念 1.1.1集成学习的定义 集成学习是一种通过组合多个学习器来完成学习任务的机器学习方法。它通过将多个单一模型&#xff08;也称为“基学习器”或“弱学习器”&#xff09;的输出结果进行集成&#xff0c;以获得比单一模型更好的泛化性…

批量美化图片,轻松实现多张图片描边,让图片瞬间焕发新生!

图片已成为我们日常生活中不可或缺的一部分。无论是社交媒体上的个人分享&#xff0c;还是商业宣传中的产品展示&#xff0c;高质量、精美的图片都扮演着至关重要的角色。然而&#xff0c;对于许多人来说&#xff0c;图片处理仍然是一个令人头疼的问题。现在&#xff0c;我们为…

激动,五四青年节,拿下YashanDB认证YCP

&#x1f4e2;&#x1f4e2;&#x1f4e2;&#x1f4e3;&#x1f4e3;&#x1f4e3; 作者&#xff1a;IT邦德 中国DBA联盟(ACDU)成员&#xff0c;10余年DBA工作经验&#xff0c; Oracle、PostgreSQL ACE CSDN博客专家及B站知名UP主&#xff0c;全网粉丝10万 擅长主流Oracle、My…

SpringTask定时任务

SpringBoot项目定时任务 首先在启动类引入注解EnableScheduling然后在方法中加注解Scheduled(cron“”)cron表达式 生成cron https://www.pppet.net/

牛客热题:链表中的倒数最后K个节点

&#x1f4df;作者主页&#xff1a;慢热的陕西人 &#x1f334;专栏链接&#xff1a;力扣刷题日记 &#x1f4e3;欢迎各位大佬&#x1f44d;点赞&#x1f525;关注&#x1f693;收藏&#xff0c;&#x1f349;留言 文章目录 牛客热题&#xff1a;链表中的倒数最后K个节点题目链…

PHP医疗不良事件上报系统源码 AEMS开发工具vscode+ laravel8 医院安全(不良)事件报告系统源码 可提供演示

PHP医疗不良事件上报系统源码 AEMS开发工具vscode laravel8 医院安全&#xff08;不良&#xff09;事件报告系统源码 可提供演示 医院安全不良事件报告系统&#xff08;AEMS&#xff09;&#xff1b;分为外部报告系统和内部报告系统两类。内部报告系统主要以个人为报告单位&…

《苍穹外卖》Day12部分知识点记录——数据统计-Excel报表

一、工作台 需求分析和设计 接口设计 今日数据接口订单管理接口菜品总览接口套餐总览接口订单搜索&#xff08;已完成&#xff09;各个状态的订单数量统计&#xff08;已完成&#xff09; 代码实现 今日数据接口 1. WorkspaceController 注意不要导错包了 package com.sk…

【c++】继承学习(二):探索 C++ 中派生类的默认机制与静态成员共享

&#x1f525;个人主页&#xff1a;Quitecoder &#x1f525;专栏&#xff1a;c笔记仓 目录 1.派生类的默认成员函数2.继承与友元3.继承与静态成员 朋友们大家好&#xff0c;本篇文章我们来学习继承的第二部分 1.派生类的默认成员函数 来看下面的类&#xff1a; class Person…

K8S执行完毕kubectl init xxx 执行 kubectl get ns 报错才connect: connection refused

问题场景&#xff1a; 在安装完毕K8S之后&#xff0c;执行 kubectl get ns 报错&#xff1a; [rootmaster ~]# kubectl get pods E0501 08:34:55.770030 11268 memcache.go:265] couldnt get current server API group list: Get "https://192.168.1.100:6443/api?ti…

深度学习项目实战:Python深度强化学习求解动态旅行商问题

深度强化学习&#xff08;Deep Reinforcement Learning,DRL&#xff09;可以用于解决优化问题&#xff0c;尤其是具有复杂、高维度的状态空间和动作空间的问题。它结合了深度学习的强大表示能力和强化学习的学习框架&#xff0c;深度神经网络可以学习复杂的特征和模式&#xff…