React 图片查看器

作者:陈佳鑫
时间:2023-5-04

图片查看器

本组件使用forwardRefuseImperativeHandle编写,可在父组件通过 ref 直接操作,减少了父子组件通信事件,使组件更加便利
本组件支持通过点击切换图片,通过左右键盘按键操作

组件代码

import { LeftOutlined, RightOutlined } from '@ant-design/icons'
import { Modal } from 'antd'
import React, {
  forwardRef,
  useCallback,
  useEffect,
  useImperativeHandle,
  useState
} from 'react'
import styled from 'styled-components'

const TableImg = styled.div`
  display: flex;
  overflow-x: scroll;
  margin-bottom: 5px;
  img {
    width: 60px;
    height: 60px;
    margin: 5px;
    cursor: pointer;
  }
  ::-webkit-scrollbar {
    width: 1px;
    height: 8px;
  }
  ::-webkit-scrollbar-thumb {
    border-radius: 10px;
    box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.2);
    background: #fc9611;
  }
`
const LeftDiv = styled.div`
  cursor: pointer;
  position: absolute;
  top: 55%;
  background: #000;
  opacity: 0.3;
  width: 50px;
  height: 50px;
  line-height: 55px;
  text-align: center;
  border-radius: 50px;
`

const RightDiv = styled.div`
  cursor: pointer;
  position: absolute;
  top: 55%;
  right: 25px;
  background: #000;
  opacity: 0.3;
  width: 50px;
  height: 50px;
  line-height: 55px;
  text-align: center;
  border-radius: 50px;
`

const ImgCheck = forwardRef(
  (
    props: { title?: string },
    ref: React.ForwardedRef<{ show: (arr: string[], select: number) => void }>
  ) => {
    useImperativeHandle(ref, () => ({
      show: (arr, select) => {
        setImgArr(arr)
        setSelect(select)
        setVisible(true)
      }
    }))
    const [visible, setVisible] = useState<boolean>(false)
    const [select, setSelect] = useState<number>(0)
    const [imgArr, setImgArr] = useState<string[]>([])

    const onKeyDown = useCallback(
      (event: KeyboardEvent) => {
        if (event.code === 'ArrowLeft') {
          setSelect((prevState) => {
            return prevState === 0 ? prevState : prevState - 1
          })
        } else if (event.code === 'ArrowRight') {
          setSelect((prevState) => {
            return prevState === imgArr.length - 1 ? prevState : prevState + 1
          })
        }
      },
      [imgArr]
    )

    useEffect(() => {
      if (imgArr.length > 1) {
        if (visible) {
          window.addEventListener('keydown', onKeyDown, false)
        } else {
          window.removeEventListener('keydown', onKeyDown, false)
        }
      }
    }, [visible])

    return (
      <Modal
        visible={visible}
        title={`${props.title || '图片'}${imgArr.length}/${select + 1}`}
        footer={null}
        zIndex={9999}
        onCancel={() => {
          setVisible(false)
          setSelect(0)
        }}
      >
        <TableImg>
          {imgArr.map((item: string, index: number) => {
            return (
              <img
                src={`${item}!80`}
                key={index}
                style={{
                  pointerEvents: 'none',
                  border: select === index ? '2px solid #fc9611' : 'none'
                }}
                onClick={() => {
                  setSelect(index)
                }}
              />
            )
          })}
        </TableImg>
        <img alt="example" style={{ width: '100%' }} src={imgArr[select]} />
        {select > 0 && (
          <LeftDiv onClick={() => setSelect(select - 1)}>
            <LeftOutlined
              style={{ fontSize: 22, fontWeight: 'bold', color: '#fff' }}
            />
          </LeftDiv>
        )}
        {select < imgArr.length - 1 && (
          <RightDiv onClick={() => setSelect(select + 1)}>
            <RightOutlined
              style={{ fontSize: 22, fontWeight: 'bold', color: '#fff' }}
            />
          </RightDiv>
        )}
      </Modal>
    )
  }
)
export default ImgCheck

组件调用

const imgRef = createRef<{ show: (arr: string[], select: number) => void }>()

<ImgCheck title={props.title} ref={imgRef} />
Last Updated:
Contributors: 1102166242@qq.com, cjx