UNPKG

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