1 | import React, { useEffect, useState, useRef } from "react";
|
2 | import "cropperjs/dist/cropper.css";
|
3 | import Cropper from "cropperjs";
|
4 | import styled from "styled-components";
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 |
|
11 |
|
12 | export 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 |
|
79 |
|
80 | const 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 |
|
90 | const 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 |
|
104 | const Left = styled.div`
|
105 | flex-grow: 1;
|
106 | flex-direction: column;
|
107 | height: 100%;
|
108 | display: flex;
|
109 | `;
|
110 |
|
111 | const Title = styled.div`
|
112 | padding: 15px;
|
113 | `;
|
114 |
|
115 | const RightTitle = styled(Title)`
|
116 | padding-left: 0;
|
117 | `;
|
118 |
|
119 | const Workspace = styled.div`
|
120 | flex-grow: 1;
|
121 | `;
|
122 |
|
123 | const 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 |
|
136 | const Preview = styled.div`
|
137 | width: 257px;
|
138 | height: 257px;
|
139 | overflow: hidden;
|
140 | `;
|
141 |
|
142 | const Img = styled.img`
|
143 | max-width: 100%;
|
144 | `;
|
145 | const Actions = styled.div`
|
146 | margin-top: 20px;
|
147 | `;
|
148 |
|
149 | const 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 |
|
160 | const ButtonOK = styled(Button)`
|
161 | background: rgb(13, 91, 232);
|
162 | `;
|