TypeScript中实现分页展示的两种方式

1. 在后端接口做分页处理

API:

@server.route("/api/get_container2", methods=['get'])
def get_container2():
    """
    images2 --- center
    """
    sql = mysql.fetchall("select * from xysh_imgs2 where is_delete = '0' order by text2 desc")
    page = request.args.get('page', 1, type=int)  # 默认页码为1
    limit = request.args.get('limit', 6, type=int)  # 默认每页显示10条记录
    page = max(1, page)
    limit = max(1, limit)
    total_count = len(sql)  # 计算图片总数
    total_pages = (total_count + limit - 1) // limit  # 计算总页数
    start_index = (page - 1) * limit
    end_index = start_index + limit
    page_data = sql[start_index:min(end_index, len(sql))]
    return {"data": page_data, "total_pages": total_pages}

前端:

const [currentPage, setCurrentPage] = useState(1)
const [IMAGE2,setImage2] = useState([])
const [totalPages, setTotalPages] = useState<number | null>(null);
const [pageNumbers, setPageNumbers] = useState<number[]>([]);
const fetchData = async (page : number) => {
 await new Promise(resolve => {setTimeout(resolve, 300)})
 try {
   const response = await get_container2({ page });
   const { data, total_pages } = response;
   setImage2(data);
   setTotalPages(total_pages);
   if (total_pages !== null) {
     const newPageNumbers = Array.from({ length: total_pages }, (_, i) => i + 1);
     setPageNumbers(newPageNumbers);
   }
 } catch (error) {
   console.error('Error fetching images:', error);
 }
};
// 翻页的逻辑
useEffect(() => {
 fetchData(currentPage);
}, [currentPage]);
const handlePreviousPage = () => {
 if (currentPage > 1) {
   setCurrentPage(currentPage - 1);
 }
};

const handleNextPage = () => {
 if (totalPages !== null && currentPage < totalPages) {
   setCurrentPage(currentPage + 1);
 }
};

const handlePageClick = (pageNumber: number) => {
 if (totalPages !== null && pageNumber >= 1 && pageNumber <= totalPages) {
   setCurrentPage(pageNumber);
 }
};

const isPreviousDisabled = currentPage === 1;
const isNextDisabled = totalPages !== null && currentPage === totalPages;

按钮点击事件:

<div className={'FlipPage'}>
	<ConfigProvider
	theme={{
	  components: {
	    Button: {
	      defaultBg: "#ffffff",
	      defaultBorderColor: "#ccc"
	    },
	  },
	}}>
	<Button onClick={handlePreviousPage} disabled={isPreviousDisabled} shape="round" size={"large"} className={'button-l'}>prey</Button>
	{pageNumbers.map((pageNumber) => (
	  <Button
	    key={pageNumber}
	    onClick={() => handlePageClick(pageNumber)}
	    disabled={currentPage === pageNumber}
	    shape="round"
	    size="large"
	    className={currentPage === pageNumber ? 'button-active' : 'button-page'}
	  >
	    {pageNumber}
	  </Button>
	))}
	<Button onClick={handleNextPage} disabled={isNextDisabled} shape="round" size={"large"} className={'button-r'}>next</Button>
	</ConfigProvider>
</div>

CSS:

/*翻页按钮的CSS样式*/
.FlipPage {
  margin-bottom: 30px;
  text-align: center;
}

.button-l {
  position: absolute;
  left: 0;
  font-size: 18px;
  width: 140px;
  height: 50px;
  transition: all .4s ease-in-out;
}
.button-l::before {
  content: '';
  width: 12px;
  height: 14px;
  position: absolute;
  left: 20%;
  top: 50%;
  transform: translateY(-40%);
  background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAOCAYAAAFsus16AAAACXBIWXMAAAsTAAALEwEAmpwYAAAF8WlUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4gPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENvcmUgNS42LWMxNDUgNzkuMTYzNDk5LCAyMDE4LzA4LzEzLTE2OjQwOjIyICAgICAgICAiPiA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPiA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIgeG1sbnM6cGhvdG9zaG9wPSJodHRwOi8vbnMuYWRvYmUuY29tL3Bob3Rvc2hvcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RFdnQ9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZUV2ZW50IyIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ0MgMjAxOSAoV2luZG93cykiIHhtcDpDcmVhdGVEYXRlPSIyMDIyLTA3LTE4VDE4OjM1OjMxKzA4OjAwIiB4bXA6TW9kaWZ5RGF0ZT0iMjAyMi0wNy0xOFQyMDowNCswODowMCIgeG1wOk1ldGFkYXRhRGF0ZT0iMjAyMi0wNy0xOFQyMDowNCswODowMCIgZGM6Zm9ybWF0PSJpbWFnZS9wbmciIHBob3Rvc2hvcDpDb2xvck1vZGU9IjMiIHBob3Rvc2hvcDpJQ0NQcm9maWxlPSJzUkdCIElFQzYxOTY2LTIuMSIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDowNjkxNWQ1MS00ZjdkLWYxNGQtYTQ1NC05ZjdjYWI5YzA1MzciIHhtcE1NOkRvY3VtZW50SUQ9ImFkb2JlOmRvY2lkOnBob3Rvc2hvcDo5Mzk3NTA5Yy02ZGI4LTBlNDQtYjE1OC0zZDA2ZWU2NjYxZmYiIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDpkZWMyODZkNC05MWNiLTJjNDYtYjM1YS1hNzQ4NGQ4YWNhYmYiPiA8eG1wTU06SGlzdG9yeT4gPHJkZjpTZXE+IDxyZGY6bGkgc3RFdnQ6YWN0aW9uPSJjcmVhdGVkIiBzdEV2dDppbnN0YW5jZUlEPSJ4bXAuaWlkOmRlYzI4NmQ0LTkxY2ItMmM0Ni1iMzVhLWE3NDg0ZDhhY2FiZiIgc3RFdnQ6d2hlbj0iMjAyMi0wNy0xOFQxODozNTozMSswODowMCIgc3RFdnQ6c29mdHdhcmVBZ2VudD0iQWRvYmUgUGhvdG9zaG9wIENDIDIwMTkgKFdpbmRvd3MpIi8+IDxyZGY6bGkgc3RFdnQ6YWN0aW9uPSJzYXZlZCIgc3RFdnQ6aW5zdGFuY2VJRD0ieG1wLmlpZDowNjkxNWQ1MS00ZjdkLWYxNGQtYTQ1NC05ZjdjYWI5YzA1MzciIHN0RXZ0OndoZW49IjIwMjItMDctMThUMjA6MDQrMDg6MDAiIHN0RXZ0OnNvZnR3YXJlQWdlbnQ9IkFkb2JlIFBob3Rvc2hvcCBDQyAyMDE5IChXaW5kb3dzKSIgc3RFdnQ6Y2hhbmdlZD0iLyIvPiA8L3JkZjpTZXE+IDwveG1wTU06SGlzdG9yeT4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz4ENtFkAAAAqUlEQVQokW3RSZLCMBBE0SeF78P5wA0eGPoAHNi9EBVdIVQ7Z+ZXpazi9IajalM4vVUcJTyU5P87C9aKGWvEHthhinwDGwPXSKBMOOOVNoCK3yQc2PqjwoCtjsTo+CVGxRDXOD+WP5IhG7n/kQ3aT9my2deNueV9udjUiT+4j4LxEcCcSg+DGXji0un7KEy73Ky9Rd5wk96lB2KuH3BP2heYgZjlAy4j8A9gvC8MEaYeDAAAAABJRU5ErkJggg==);
  transition: all .4s ease-in-out;
}
.button-l:hover {
  background-color: #002f93 !important;
  color: #ffff !important;
}
.button-l:hover::before {
  background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAOCAYAAAFsus16AAAACXBIWXMAAAsTAAALEwEAmpwYAAAF+mlUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4gPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENvcmUgNS42LWMxNDUgNzkuMTYzNDk5LCAyMDE4LzA4LzEzLTE2OjQwOjIyICAgICAgICAiPiA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPiA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIgeG1sbnM6cGhvdG9zaG9wPSJodHRwOi8vbnMuYWRvYmUuY29tL3Bob3Rvc2hvcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RFdnQ9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZUV2ZW50IyIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ0MgMjAxOSAoV2luZG93cykiIHhtcDpDcmVhdGVEYXRlPSIyMDIyLTA3LTE4VDE4OjM1OjA1KzA4OjAwIiB4bXA6TW9kaWZ5RGF0ZT0iMjAyMi0wNy0xOFQyMDowNDoxMyswODowMCIgeG1wOk1ldGFkYXRhRGF0ZT0iMjAyMi0wNy0xOFQyMDowNDoxMyswODowMCIgZGM6Zm9ybWF0PSJpbWFnZS9wbmciIHBob3Rvc2hvcDpDb2xvck1vZGU9IjMiIHBob3Rvc2hvcDpJQ0NQcm9maWxlPSJzUkdCIElFQzYxOTY2LTIuMSIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDo3YWE0NWQ3ZS1mNzk5LTJlNGUtYTY3YS1hNGQyMzg3OTA5ZDMiIHhtcE1NOkRvY3VtZW50SUQ9ImFkb2JlOmRvY2lkOnBob3Rvc2hvcDowNDlkMDllYi1kOWQwLTgwNDUtYWE5Yy04MmVjYTA0M2EzOTAiIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDplMmE5MTgwYi01YWIwLThjNDEtODc4ZC05ZGQ1ZWE2ZWI5MTYiPiA8eG1wTU06SGlzdG9yeT4gPHJkZjpTZXE+IDxyZGY6bGkgc3RFdnQ6YWN0aW9uPSJjcmVhdGVkIiBzdEV2dDppbnN0YW5jZUlEPSJ4bXAuaWlkOmUyYTkxODBiLTVhYjAtOGM0MS04NzhkLTlkZDVlYTZlYjkxNiIgc3RFdnQ6d2hlbj0iMjAyMi0wNy0xOFQxODozNTowNSswODowMCIgc3RFdnQ6c29mdHdhcmVBZ2VudD0iQWRvYmUgUGhvdG9zaG9wIENDIDIwMTkgKFdpbmRvd3MpIi8+IDxyZGY6bGkgc3RFdnQ6YWN0aW9uPSJzYXZlZCIgc3RFdnQ6aW5zdGFuY2VJRD0ieG1wLmlpZDo3YWE0NWQ3ZS1mNzk5LTJlNGUtYTY3YS1hNGQyMzg3OTA5ZDMiIHN0RXZ0OndoZW49IjIwMjItMDctMThUMjA6MDQ6MTMrMDg6MDAiIHN0RXZ0OnNvZnR3YXJlQWdlbnQ9IkFkb2JlIFBob3Rvc2hvcCBDQyAyMDE5IChXaW5kb3dzKSIgc3RFdnQ6Y2hhbmdlZD0iLyIvPiA8L3JkZjpTZXE+IDwveG1wTU06SGlzdG9yeT4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz74oLWoAAAAq0lEQVQokW3RW5LCMBBD0WNXNsXShgB5kBl2ww6pzEfoosu4/yLpuuW4vJ4n2KtjitfzpGIv4aF8/ORMmCtGzBHbsMIQeQgGrpFAGfCDv7QBVDySsGNpjwoDltoTo+OXGBVDnOP8WL4lQzZy/z0bHD9lyWZbN+aW9+ViQyNecO8F4yOAMZXuBjPwi3Ojr70wx+VGx1vkDTfpXVog5voG16R9gRmImd7g1AP/Abh7Nvr5qnPSAAAAAElFTkSuQmCC);
}

.button-r {
  position: absolute;
  right: 0;
  font-size: 18px;
  width: 140px;
  height: 50px;
  transition: all .4s ease-in-out;
}
.button-r::before {
  content: '';
  width: 12px;
  height: 14px;
  position: absolute;
  right: 20%;
  top: 50%;
  transform: translateY(-40%);
  background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAOCAYAAAAbvf3sAAAAj0lEQVQokYXSyQ1CMQyE4f8BRwqgC1p4cKQlxPZEBzTE0hVi00hESqwx+JLIni+XuGN+2gM72lLvgKkxs9UZ6IC+Guv+Bi6RCOh0aAG8gKsDv9CzRjXI0BJ4ADcH/iIHCsKg+8ilv+Vm0wzoD7ahdwTWDmThjS4RuPBQwhFk4WZtCnBh9eKOMUnCCur1toAP87Uif6QrvmgAAAAASUVORK5CYII=);
  transition: all .4s ease-in-out;
}
.button-r:hover {
  background-color: #002f93 !important;
  color: #ffff !important;
}
.button-r:hover::before {
  background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAOCAYAAAAbvf3sAAAAkklEQVQokY2SzQ3CMAxGX1uOrMAg3NopGAbRAu08nQHYqz8yaqQk+lzVF0fOe7FlpZjG6xPoSMNqL0RU3e3yAQqgjq7tvADfXDHBspIaYAZ+StiTplgqD8zeA3dP8KQhSCe1iU1athxLs+qw1/3sCTZSq8ZSggc/VFsFvwOcCx6cfJsgKNhq+R/7r1XBBtrraQArYOsjbdwjVQMAAAAASUVORK5CYII=);
}

2. 在前端调用接口做处理

前端:

const [currentPage, setCurrentPage] = useState(1);
const [allImages, setAllImages] = useState([]);
const [currentImages, setCurrentImages] = useState([]);
const [limit] = useState(9); // 设置每页显示的图片数量

const fetchAllImages = async () => {
    try {
      const response = await get_container2({});
      const { data} = response;
      setAllImages(data);
      setCurrentImages(data.slice(0, limit)); // 显示第一页的图片
      setCurrentPage(1);
    } catch (error) {
      console.error('Error fetching images:', error);
    }
  };

useEffect(() => {
    fetchAllImages();
  }, []);

// 更新当前页显示的图片
  const updateCurrentImages = (page: number) => {
    const startIndex = (page - 1) * limit;
    const endIndex = Math.min(startIndex + limit, allImages.length);
    setCurrentImages(allImages.slice(startIndex, endIndex));
  };

// 上一页 按钮的逻辑
const handlePreviousPage = () => {
    	if (currentPage > 1) {
      	setCurrentPage(currentPage - 1);
      	updateCurrentImages(currentPage - 1);
    	}
  	};

// 下一页 按钮的逻辑
  const handleNextPage = () => {
    if (currentPage < Math.ceil(allImages.length / limit)) {
      setCurrentPage(currentPage + 1);
      updateCurrentImages(currentPage + 1);
    }
  };

// 中间数字点击的逻辑
  const handlePageClick = (pageNumber: number) => {
    if (pageNumber >= 1 && pageNumber <= Math.ceil(allImages.length / limit)) {
      setCurrentPage(pageNumber);
      updateCurrentImages(pageNumber);
    }
  };

// 上一页`下一页按钮置灰的逻辑
  const isPreviousDisabled = currentPage === 1;
  const isNextDisabled = currentPage >= Math.ceil(allImages.length / limit);

// 中间数字页面的按钮
const renderPageNumbers = () => {
    if (!allImages.length) return null; // 如果没有图片数据,则不显示页码
    const totalPages = Math.ceil(allImages.length / limit);
    const pageButtons = [];
    for (let i = 1; i <= totalPages; i++) {
      pageButtons.push(
        <Button
          key={`page-${i}`}
          onClick={() => handlePageClick(i)}
          disabled={currentPage === i} // 当前页码按钮不可点击
          shape="round"
          size="large"
        >
          {i}
        </Button>
      );
    }
    return pageButtons;
  };

// 上一页`下一页按钮
  const renderPaginationButtons = () => (
    <div className={'FlipPage'}>
      <ConfigProvider
        theme={{
          components: {
            Button: {
              defaultBg: "#ffffff",
              defaultBorderColor: "#ccc"
            },
          },
        }}>
        <Button onClick={handlePreviousPage} disabled={isPreviousDisabled} shape="round" size={"large"} className={'button-l'}>prey</Button>

        {renderPageNumbers()}

        <Button onClick={handleNextPage} disabled={isNextDisabled} shape="round" size={"large"} className={'button-r'}>next</Button>
      </ConfigProvider>
    </div>
  );

这里的CSS与上方的CSS一样。
·在页面将 renderPaginationButtons 调用即可·
在这里插入图片描述

后端:

@server.route("/api/get_container2", methods=['get'])
def get_container2():
    """
    第二组图片的接口,返回所有数据
    """
    sql = mysql.fetchall("select * from xysh_imgs2 where is_delete = '0' order by text2 desc")
    return { "data": sql, "total_count": len(sql) }
TypeScript ,将数据库数据展示前端通常涉及以下几个步骤: 1. **连接数据库**:使用像 `TypeORM`、`Sequelize` 或 `MongoDB native driver` 等 ORM(对象关系映射库)来连接你的数据库,它们允许你在 TypeScript 操作 SQL 或 NoSQL 数据。 ```typescript import { createConnection } from 'typeorm'; createConnection().then(async connection => { // 这里可以查询数据 }); ``` 2. **查询数据**:编写 SQL 查询语句或使用 ORM 的 API 来获取需要的数据。例如,设你想从一个用户表获取所有用户信息: ```typescript const userRepository = connection.getRepository(User); const users = await userRepository.find(); ``` 3. **转换数据模型**:查询结果通常是实体对象,需要将其转换为适合前端显示的 JSON 对象。你可以选择手动处理,或者使用如 `jsonify` 或 `toPlainObject` 方法: ```typescript const userArray = users.map(user => user.toPlainObject()); ``` 4. **发送到前端**:将 JSON 数据通过 Axios、Fetch 等 HTTP 客户端发送到浏览器,或者在服务端渲染时直接返回给前端。 ```typescript axios.post('/api/users', { data: userArray }) .then(response => { // 处理响应 }); ``` 5. **前端接收并显示**:在前端,通过 JavaScript 将接收到的数据绑定到视图上,比如 Angular、Vue 或 React: ```javascript users.map(user => ( <div key={user.id}> {/* 显示用户名、邮箱等属性 */} </div> )); ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值