基于react和rc-viewer封装一个图片预览组件

在项目实战开发中,图片预览是非常常见的需求,尤其是在做后台管理系统中,我们都知道在使用Vue开发的项目中,v-viewer是一个基于VueViewer.js封装的非常好用的第三方图片预览组件。其实Viewer.js也有基于React封装的版本,那就是rc-viewer

但是,在实际开发中,我们可能有很多页面都需要使用到图片预览功能,作为一个有追求的程序猿,当然无法接收相同的事情重复干。基于组件化的开发思想,今天我们将基于reactrc-viewer二次封装一个图片预览组件。

一、基本使用

1. 安装

npm install @hanyk/rc-viewer

2. 简单使用

import React, { useState } from "react";
import { Button } from "antd";
import RcViewer from "@hanyk/rc-viewer";
function Preview() {
  const [preview, setPreview] = useState(null);
  const [previewImgUrl, setPreviewImgUrl] = useState("");
  function handlePreview() {
    setPreviewImgUrl(
      "http://xxxx.oss-cn-shenzhen.aliyuncs.com/jies/settlement/2020-12-24/420325196902011112%E5%9B%BD%E5%BE%BD%E9%9D%A2%20-%20%E5%89%AF%E6%9C%AC%20(4)-20201224180454.jpg"
    );
    if (preview) {
      preview.viewer.show();
    }
  }
  const options = {
    // 是否显示下面工具栏 1 显示 0 隐藏
    toolbar: 1,
    // 关闭时的回调
    hide() {
      console.log("hide");
    },
  };
  return (
    <div>
      <Button type="primary" onClick={handlePreview}>
        预览
      </Button>
      <div style={{ display: "none" }}>
        <RcViewer
          options={options}
          ref={(v) => {
            setPreview(v);
          }}
        >
          <ul id="images">
            <li>
              <img src={previewImgUrl} alt="" />
            </li>
          </ul>
        </RcViewer>
      </div>
    </div>
  );
}
export default Preview;

二、使用 Redux 进行封装

|- src
    |- components
        |- Preview
            |- index.tsx
            import React, { useEffect, useState } from 'react';
            import RcViewer from '@hanyk/rc-viewer';
            import { useSelector } from 'react-redux';
            import store from '@/store/index';
            import { tooglePreview } from '@/store/modules/common/actionCreators';
            function Preview() {
                const [preview, setPreview] = useState(null);
                const isVisible = useSelector((state: any) => {
                    return state.getIn(['common', 'isPreviewVisible']);
                });
                // 要预览的图片
                const previewImgUrl = useSelector((state: any) => {
                    return state.getIn(['common', 'previewImgUrl']);
                });
                // 展示
                function show() {
                    if (preview) {
                        (preview as any).viewer.show();
                    }
                }
                useEffect(() => {
                    isVisible && show();
                }, [isVisible]);

                const options = {
                    // 是否显示下面工具栏 1 显示 0 隐藏
                    toolbar: 1,
                    // 关闭时的回调
                    hide() {
                        store.dispatch(tooglePreview(false));
                    },
                };
                return (
                    <div style={{ display: 'none' }}>
                        <RcViewer
                            options={options}
                            ref={(v: any) => {
                                setPreview(v);
                            }}
                        >
                            <ul id="images">
                                <li>
                                    <img src={previewImgUrl} />
                                </li>
                            </ul>
                        </RcViewer>
                    </div>
                );
            }
            export default Preview;
    |- store
        |- modules
            |- common
                |- actionCreators.ts
                import * as actionTypes from './actionTypes';
                export const tooglePreview = (payload: boolean) => ({
                    type: actionTypes.SET_PREVIEW_TOOGLE,
                    data: payload,
                });
                export const setPreviewUrl = (payload: string) => ({
                    type: actionTypes.SET_PREVIEW_URL,
                    data: payload,
                });

                |- actionTypes.ts
                // 切换预览显示隐藏
                export const SET_PREVIEW_TOOGLE = 'common/SET_PREVIEW_TOOGLE';
                // 设置预览图片地址
                export const SET_PREVIEW_URL = 'common/SET_PREVIEW_URL';

                |- index.ts
                import reducers from './reducers';
                import * as actionCreators from './actionCreators';
                import * as actionTypes from './actionTypes';
                export { reducers, actionCreators, actionTypes };

                |- reducers.ts
                import * as actionTypes from './actionTypes';
                import { fromJS } from 'immutable';
                const defaultState = fromJS({
                    // 是否显示预览
                    isPreviewVisible: false,
                    // 预览的图片地址
                    previewImgUrl: '',
                });
                export default (state = defaultState, action: any) => {
                    switch (action.type) {
                        case actionTypes.SET_PREVIEW_TOOGLE:
                            return state.set('isPreviewVisible', action.data);
                        case actionTypes.SET_PREVIEW_URL:
                            return state.set('previewImgUrl', action.data);
                        default:
                            break;
                    }
                    return state;
                };

            |- index.ts
            import { createStore, applyMiddleware, compose } from 'redux';
            import createSagaMiddleware from 'redux-saga';
            import reducer from './reducers';
            // 引入合并后的saga
            import rootSaga from './sagas';
            const sagaMiddleware = createSagaMiddleware();
            const composeEnhancers = (window as any).__REDUX_DEVTOOLS_EXTENSION_COMPOSE__
                ? (window as any).__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({})
                : compose;
            const enhancer = composeEnhancers(applyMiddleware(sagaMiddleware));
            const store = createStore(reducer, enhancer);
            // 执行saga
            sagaMiddleware.run(rootSaga);
            export default store;

            |- reducers.ts
            import { combineReducers } from 'redux-immutable';
            import { reducers as commonReducer } from './modules/common/index';
            import { reducers as businessReducer } from './modules/business/index';
            const reducer = combineReducers({
                common: commonReducer
            });
            export default reducer;

            |- sagas.ts
            import { all, fork } from 'redux-saga/effects';
            // 异步逻辑模块文件引入
            import { businessSagas } from './modules/business';
            // 合并saga,单一进入点,一次启动所有Saga
            export default function* rootSaga() {
                yield all([fork(businessSagas.default)]);
            }
    |- view
    App.tsx
    import React, { useEffect } from 'react';
    import store from '@/store/index';
    import { tooglePreview, setPreviewUrl } from '@/store/modules/common/actionCreators';
    import Preview from '@components/Preview/index';
    import { Button } from 'antd'
    function App() {
        function handlePreview(file) {
            store.dispatch(tooglePreview(true));
            store.dispatch(setPreviewUrl(file.url));
        }
        return (
            <div>
                <Button onClick={handlePreview}>预览</Button>
                <Preview />
            </div>
        );
    }
    export default App;
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 220,192评论 6 511
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,858评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 166,517评论 0 357
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,148评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,162评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,905评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,537评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,439评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,956评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,083评论 3 340
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,218评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,899评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,565评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,093评论 0 23
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,201评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,539评论 3 375
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,215评论 2 358

推荐阅读更多精彩内容