• React 图片瀑布流


     思路:

    根据浏览器宽度,确定列数,请求的图片列表数据是列数的10倍,按列数取数据渲染

    Index.js:

    1. import React from 'react'
    2. import { connect } from 'react-redux'
    3. import { withRouter } from 'react-router-dom'
    4. import { SinglePageHeader } from '../../../../../components/light'
    5. import InfiniteScroll from 'react-infinite-scroll-component'
    6. import { Divider, Skeleton } from 'antd'
    7. import useList from './useList'
    8. import LazyLoad from 'react-lazy-load'
    9. import './index.css'
    10. function Index(props) {
    11. const {
    12. dataSource,
    13. isHasMore,
    14. columnCount,
    15. handleSearch,
    16. handleImgDrawSameStyleClick,
    17. } = useList(props)
    18. return (
    19. <div className="m-ai-img-wrap-box">
    20. <div className={`m-ai-img-wrap-chat`}>
    21. <SinglePageHeader title="AI绘画作品展示">SinglePageHeader>
    22. <div className="m-ai-img-list" id="scrollableDiv">
    23. <InfiniteScroll
    24. dataLength={dataSource.length}
    25. next={handleSearch}
    26. refreshFunction={() => handleSearch({ page: 1, isRefresh: true })}
    27. pullDownToRefresh
    28. pullDownToRefreshThreshold={50}
    29. pullDownToRefreshContent={
    30. <h3 style={{ textAlign: 'center' }}> 下拉刷新h3>
    31. }
    32. releaseToRefreshContent={
    33. <h3 style={{ textAlign: 'center' }}> 释放刷新h3>
    34. }
    35. hasMore={isHasMore}
    36. loader={
    37. <Skeleton
    38. avatar
    39. paragraph={{
    40. rows: 3,
    41. }}
    42. active
    43. className="m-h5-lesson-play-skeleton"
    44. />
    45. }
    46. endMessage={
    47. dataSource.length === 0 ? null : (
    48. <Divider plain>已经到底啦~Divider>
    49. )
    50. }
    51. scrollableTarget="scrollableDiv"
    52. >
    53. <div className="m-ai-img-list-inner">
    54. {Array.from({ length: columnCount }, () => '').map(
    55. (item, index) => (
    56. <div className="m-ai-img-list-column" key={index}>
    57. {dataSource
    58. .filter(
    59. (item, dataSourceIndex) =>
    60. dataSourceIndex % columnCount === index
    61. )
    62. .map((item) => (
    63. <div key={item.imgUid}>
    64. <LazyLoad className="m-ai-img-lazy-load">
    65. <img
    66. src={item.imgUrlCdn}
    67. className="m-ai-img"
    68. alt="图片"
    69. onClick={() => handleImgDrawSameStyleClick(item)}
    70. >img>
    71. LazyLoad>
    72. div>
    73. ))}
    74. div>
    75. )
    76. )}
    77. div>
    78. {dataSource.length === 0 ? (
    79. <Skeleton
    80. avatar
    81. paragraph={{
    82. rows: 3,
    83. }}
    84. active
    85. className="m-h5-lesson-play-skeleton"
    86. />
    87. ) : null}
    88. InfiniteScroll>
    89. div>
    90. div>
    91. div>
    92. )
    93. }
    94. const mapStateToProps = (state) => {
    95. return {
    96. collapsed: state.getIn(['light', 'collapsed']),
    97. isRNGotToken: state.getIn(['light', 'isRNGotToken']),
    98. }
    99. }
    100. const mapDispatchToProps = (dispatch) => {
    101. return {
    102. onSetState(key, value) {
    103. dispatch({ type: 'SET_LIGHT_STATE', key, value })
    104. },
    105. onDispatch(action) {
    106. dispatch(action)
    107. },
    108. }
    109. }
    110. export default connect(mapStateToProps, mapDispatchToProps)(withRouter(Index))

    useList.js:

    1. import { useState, useEffect } from 'react'
    2. import { Form } from 'antd'
    3. import Api from '../../../../../api'
    4. import { message } from 'antd'
    5. import * as clipboard from 'clipboard-polyfill/text'
    6. export default function useList(props) {
    7. const [total, setTotal] = useState(10)
    8. const [current, setCurrent] = useState(1)
    9. let tempCount = Math.floor((window.innerWidth - 10) / 180)
    10. tempCount = Math.floor((window.innerWidth - (5 + tempCount * 5)) / 180)
    11. console.log('tempCount1', tempCount)
    12. //把dataSource和pageSize单独放在一起是为了避免切换pageSize时的bug
    13. const [state, setState] = useState({
    14. dataSource: [],
    15. pageSize: tempCount * 10,
    16. })
    17. const [isHasMore, setIsHasMore] = useState(true)
    18. // eslint-disable-next-line
    19. const [username, setUsername] = useState(localStorage.getItem('username'))
    20. const [form] = Form.useForm()
    21. // eslint-disable-next-line
    22. const [initValues, setInitValues] = useState({})
    23. // eslint-disable-next-line
    24. const [columnCount, setColumnCount] = useState(tempCount)
    25. //搜索
    26. const handleSearch = ({
    27. page = current,
    28. pageSize = state.pageSize,
    29. isRefresh = false,
    30. } = {}) => {
    31. if (isRefresh) {
    32. setState({
    33. dataSource: [],
    34. pageSize: tempCount * 10,
    35. })
    36. }
    37. let searchData = { pageNum: page, pageSize }
    38. Api.h5.sdImgSearch(searchData).then((res) => {
    39. if (res.code === 200) {
    40. const { pageNum, pageSize, total } = res.data
    41. let list = res.data.list
    42. if (isRefresh) {
    43. setState({
    44. dataSource: [...list],
    45. pageSize: res.data.pageSize,
    46. })
    47. } else {
    48. setState({
    49. dataSource: [...state.dataSource, ...list],
    50. pageSize: res.data.pageSize,
    51. })
    52. }
    53. setTotal(res.data.total)
    54. const currentTemp = res.data.pageNum + 1
    55. setCurrent(currentTemp)
    56. setIsHasMore(pageNum < Math.ceil(total / pageSize))
    57. }
    58. })
    59. }
    60. //添加或编辑
    61. const handleFinish = (values) => {
    62. console.log('Success:', values)
    63. Api.h5.exchangeCodeAppUse(values).then((res) => {
    64. if (res.code === 200) {
    65. message.success('恭喜您,兑换成功')
    66. //props.history.push('/h5/index/me')
    67. }
    68. })
    69. }
    70. //校验失败
    71. const handleFinishFailed = (errorInfo) => {
    72. console.log('Failed:', errorInfo)
    73. }
    74. //退出
    75. const handleQuit = () => {
    76. Api.light.userLogout().then((res) => {
    77. if (res.code === 200) {
    78. props.history.push('/h5/login')
    79. window.localStorage.removeItem('username')
    80. window.localStorage.removeItem('token')
    81. }
    82. })
    83. }
    84. //跳转
    85. const handleJumpPage = (path) => {
    86. // eslint-disable-next-line
    87. props.history.push(path)
    88. }
    89. const handleCopy = (text) => {
    90. clipboard.writeText(text).then(() => {
    91. message.success('复制成功')
    92. })
    93. }
    94. const handleImgDrawSameStyleClick = (item) => {
    95. console.log(item)
    96. props.history.push(
    97. `/single/home/sdSimple?modelId=${item.id}&name=${item.name}&link=${item.link}&imgUid=${item.imgUid}`
    98. )
    99. }
    100. useEffect(() => {
    101. if (window.platform === 'rn') {
    102. if (props.isRNGotToken === true) {
    103. handleSearch()
    104. }
    105. } else {
    106. handleSearch()
    107. }
    108. // eslint-disable-next-line
    109. }, [props.isRNGotToken])
    110. return {
    111. username,
    112. form,
    113. initValues,
    114. dataSource: state.dataSource,
    115. total,
    116. current,
    117. pageSize: state.pageSize,
    118. isHasMore,
    119. columnCount,
    120. handleFinish,
    121. handleFinishFailed,
    122. handleQuit,
    123. handleJumpPage,
    124. handleCopy,
    125. handleSearch,
    126. handleImgDrawSameStyleClick,
    127. }
    128. }

    index.css:

    1. .m-ai-img-wrap-box{display: flex;justify-content: center;background: #ddd;background: #ddd;position: absolute;top: 0;left: 0;right: 0;bottom: 0;overflow: hidden;}
    2. .m-ai-img-wrap-chat{position: relative; display: flex;flex-direction: column;width: 100%;background: #ededed;}
    3. .m-ai-img-main{flex:1;display: flex;flex-direction: column;overflow-y: auto;}
    4. .m-ai-img-list{flex: 1;padding: 0px 0;overflow-y: auto;}
    5. .m-ai-img-list-inner{position: relative;padding: 0 0 0 5px; display: flex; flex-wrap: wrap;justify-content: center;}
    6. .m-ai-img-list-column{display: flex;flex-direction: column;width: 175px;margin: 0 5px 0 0;}
    7. .m-ai-img-lazy-load{position: relative;min-width: 175px; display: flex;flex-direction: column;justify-content: center; min-height: 175px;margin: 0 0 5px 0;border-radius: 5px; background: #dddddd;}
    8. .m-ai-img{width: 175px;border-radius: 5px;}

    效果图:

    参考链接:

    https://chat.xutongbao.top/

  • 相关阅读:
    【洛谷】P1462 通往奥格瑞玛的道路
    [微前端实战]---035react16 - 资讯视频视频详情页面
    JAVA环境变量细讲与配置
    Spring中shutdown hook作用
    Javascript享元模式
    测试电脑GPU性能代码
    VMware 桥接模式下本机 PING 不通虚拟机的解决方法
    【linux命令讲解大全】108.磁盘配额管理及使用者限制的实施方法
    金蝶云星空各种部署架构及适用场景分享
    如何查看所有员工电脑访问网站记录?
  • 原文地址:https://blog.csdn.net/xutongbao/article/details/134038718