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 | export 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 |
|
77 | const 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 |
|
87 | const 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 |
|
101 | const Left = styled.div`
|
102 | flex-grow: 1;
|
103 | flex-direction: column;
|
104 | height: 100%;
|
105 | display: flex;
|
106 | `;
|
107 |
|
108 | const Title = styled.div`
|
109 | padding: 15px;
|
110 | `;
|
111 |
|
112 | const RightTitle = styled(Title)`
|
113 | padding-left: 0;
|
114 | `;
|
115 |
|
116 | const Workspace = styled.div`
|
117 | flex-grow: 1;
|
118 | `;
|
119 |
|
120 | const 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 |
|
133 | const Preview = styled.div`
|
134 | width: 257px;
|
135 | height: 257px;
|
136 | overflow: hidden;
|
137 | `;
|
138 |
|
139 | const Img = styled.img`
|
140 | max-width: 100%;
|
141 | `;
|
142 | const Actions = styled.div`
|
143 | margin-top: 20px;
|
144 | `;
|
145 |
|
146 | const 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 |
|
157 | const ButtonOK = styled(Button)`
|
158 | background: rgb(13, 91, 232);
|
159 | `;
|