UNPKG

3.3 kBJavaScriptView Raw
1import React, { useEffect, useState, useRef } from "react";
2import "cropperjs/dist/cropper.css";
3import Cropper from "cropperjs";
4import styled from "styled-components";
5/**
6 * @param {File} file
7 * @param {Object} cropper - cropperjs options
8 * @param {Function} onSubmit(base64) - 回调函数, 参数中包含裁切图片的base64
9 * @param {Number} width - 需要的图片宽度, 高度根据比例自动计算
10 */
11export default function Crop({ file, cropper, onSubmit, width = 160 }) {
12 const [show, setShow] = useState(false);
13 const [src, setsrc] = useState("");
14 const img = useRef(null);
15 const preview = useRef(null);
16 const crop = useRef(null);
17
18 useEffect(() => {
19 if (file) {
20 const reader = new FileReader();
21 reader.readAsDataURL(file);
22 reader.onload = e => {
23 setShow(true);
24 setsrc(e.target.result);
25 };
26 }
27 }, [file]);
28
29 const onImageLoad = e => {
30 crop.current = new Cropper(img.current, {
31 aspectRatio: 16 / 9,
32 viewMode: 1,
33 preview: preview.current,
34 ...cropper
35 });
36 };
37
38 const close = () => {
39 setShow(false);
40 crop.current.destroy();
41 };
42
43 const submit = () => {
44 const canvas = crop.current.getCroppedCanvas({ width, minWidth: width });
45 const dataURL = canvas.toDataURL("image/jpeg");
46 onSubmit(dataURL);
47 close();
48 };
49
50 const display = { display: show ? "block" : "none" };
51
52 if (!file) return null;
53
54 return (
55 <Background style={display}>
56 <Box>
57 <Left>
58 <Title>图片裁切</Title>
59 <Workspace>
60 <Img src={src} onLoad={onImageLoad} ref={img} />
61 </Workspace>
62 </Left>
63 <Right>
64 <RightTitle>效果预览</RightTitle>
65 <Preview ref={preview} />
66 <Actions>
67 <Button onClick={close}>取消</Button>
68 <ButtonOK onClick={submit}>确定</ButtonOK>
69 </Actions>
70 </Right>
71 </Box>
72 </Background>
73 );
74}
75
76// Style
77const Background = styled.div`
78 background: rgba(0, 0, 0, 0.75);
79 width: 100%;
80 height: 100%;
81 position: fixed;
82 top: 0;
83 left: 0;
84 z-index: 20000;
85`;
86
87const Box = styled.div`
88 width: 1000px;
89 height: 600px;
90 background: white;
91 margin: auto;
92 position: absolute;
93 left: 0;
94 top: 0;
95 bottom: 0;
96 right: 0;
97 overflow: hidden;
98 display: flex;
99`;
100
101const Left = styled.div`
102 flex-grow: 1;
103 flex-direction: column;
104 height: 100%;
105 display: flex;
106`;
107
108const Title = styled.div`
109 padding: 15px;
110`;
111
112const RightTitle = styled(Title)`
113 padding-left: 0;
114`;
115
116const Workspace = styled.div`
117 flex-grow: 1;
118`;
119
120const Right = styled.div`
121 width: 300px;
122 padding: 0 20px;
123 display: flex;
124 flex-direction: column;
125 margin-left: 20px;
126 flex-shrink: 0;
127 height: 100%;
128 flex-grow: 1;
129 border-left: 1px solid rgb(235, 235, 235);
130 background: rgb(245, 245, 245);
131`;
132
133const Preview = styled.div`
134 width: 257px;
135 height: 257px;
136 overflow: hidden;
137`;
138
139const Img = styled.img`
140 max-width: 100%;
141`;
142const Actions = styled.div`
143 margin-top: 20px;
144`;
145
146const Button = styled.div`
147 padding: 10px 0;
148 text-align: center;
149 font-size: 15px;
150 background: rgb(255, 59, 0);
151 color: white;
152 margin: 10px 0;
153 cursor: pointer;
154 user-select: none;
155`;
156
157const ButtonOK = styled(Button)`
158 background: rgb(13, 91, 232);
159`;