在項目實戰(zhàn)開發(fā)中,圖片預覽是非常常見的需求,尤其是在做后臺管理系統(tǒng)中,我們都知道在使用Vue
開發(fā)的項目中,v-viewer
是一個基于Vue
和Viewer.js
封裝的非常好用的第三方圖片預覽組件。其實Viewer.js
也有基于React
封裝的版本,那就是rc-viewer
。
但是,在實際開發(fā)中,我們可能有很多頁面都需要使用到圖片預覽功能,作為一個有追求的程序猿,當然無法接收相同的事情重復干。基于組件化的開發(fā)思想,今天我們將基于react
和rc-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,
// 關(guān)閉時的回調(diào)
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,
// 關(guān)閉時的回調(diào)
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);
// 執(zhí)行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;