UNPKG

4.95 kBPlain TextView Raw
1<!-- 图片裁剪 -->
2<template>
3 <div class="crop-bg" v-show="show" style="z-index:20000">
4 <div class="crop-box" :style="boxStyle">
5 <div class="crop-title">图片裁剪</div>
6 <div class="close" @click="close">X</div>
7 <div class="crop-choose">
8 <label for="crop-input">
9 <input accept=".jpg, .jpeg, .png, .gif" id="crop-input" ref="input" type="file" @change="change" capture>
10 <span class="crop-btn">选择文件</span>
11 </label>
12 <button v-show="ready" class="crop-btn crop-btn-crop" @click="crop">裁切图片</button>
13 </div>
14 <div class="crop-content" :style="contentStyle">
15 <img :src="src" @load="start" ref="img" class="thumb">
16 </div>
17 </div>
18 </div>
19</template>
20<script>
21/**
22 *<yn-crop :visible.sync="shwoCrop" @crop="onCrop" :layout="[700,500]" :size="[160,160]" />
23 */
24import Cropper from "cropperjs";
25import "cropperjs/dist/cropper.css";
26export default {
27 props: {
28 visible: {
29 type: Boolean,
30 default: false
31 },
32 layout: {
33 type: Array,
34 default: () => [800, 600] //[width,height]
35 },
36 size: {
37 type: Array,
38 default: () => [200, 200]
39 }
40 },
41 data() {
42 return {
43 show: false,
44 src: "",
45 cropper: null,
46 ready: false
47 };
48 },
49
50 watch: {
51 visible(val) {
52 this.show = val;
53 }
54 },
55 computed: {
56 ratio() {
57 return this.size[0] / this.size[1];
58 },
59 boxStyle() {
60 return {
61 width: this.layout[0] + "px",
62 height: this.layout[1] + "px"
63 };
64 },
65 contentStyle() {
66 return {
67 height: this.layout[1] - 40 + "px"
68 };
69 },
70 previewStyle() {
71 const width = this.layout[0] * 0.3 * 0.8;
72 return {
73 width: width + "px",
74 height: width * this.ratio + "px"
75 };
76 }
77 },
78 methods: {
79 prevent(e) {
80 e.stopPropagation();
81 },
82 start() {
83 const self = this;
84 this.stop();
85 this.cropper = new Cropper(this.$refs.img, {
86 aspectRatio: this.ratio,
87 minCropBoxWidth: this.size[0],
88 minCropBoxHeight: this.size[1],
89 ready: () => (self.ready = true)
90 });
91 },
92 read(files) {
93 return new Promise((resolve, reject) => {
94 if (!files || files.length === 0) {
95 return resolve();
96 }
97 const file = files[0];
98 if (/^image\/\w+$/.test(file.type)) {
99 const reader = new FileReader();
100 reader.onload = () => {
101 this.src = reader.result;
102 resolve();
103 };
104 reader.onerror = reject;
105 reader.onabort = reject;
106 reader.readAsDataURL(file);
107 } else {
108 reject("Please choose an image file.");
109 }
110 });
111 },
112 //裁切图片
113 crop() {
114 const canvas = this.cropper.getCroppedCanvas({
115 width: this.size[0], //需要的尺寸
116 height: this.size[1]
117 });
118 const base64 = canvas.toDataURL();
119 this.$emit("crop", base64);
120 this.close();
121 },
122 change({ target }) {
123 this.read(target.files)
124 .then(() => (target.value = ""))
125 .catch(e => {
126 target.value = "";
127 this.alert(e);
128 });
129 },
130 alert(e) {
131 window.alert(e && e.message ? e.message : e);
132 },
133 close() {
134 this.src = "";
135 this.stop();
136 this.$emit("update:visible", false);
137 },
138 stop() {
139 if (this.cropper) {
140 this.cropper.destroy();
141 this.cropper = null;
142 this.ready = false;
143 }
144 }
145 }
146};
147</script>
148<style scoped lang="scss">
149.crop-bg {
150 position: fixed;
151 width: 100%;
152 height: 100%;
153 left: 0;
154 top: 0;
155 background: rgba(0, 0, 0, 0.281);
156 user-select: none;
157 z-index: 2000;
158}
159.crop-box {
160 position: absolute;
161 top: 0;
162 bottom: 0;
163 left: 0;
164 right: 0;
165 margin: auto;
166 background: rgb(255, 255, 255);
167 width: 600px;
168 height: 400px;
169}
170.crop-title {
171 height: 50px;
172 line-height: 50px;
173 text-indent: 20px;
174 background: rgb(245, 245, 245);
175 position: relative;
176 border-bottom: 1px solid #d4d4d4;
177}
178.crop-content {
179 overflow: hidden;
180 background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAAA3NCSVQICAjb4U/gAAAABlBMVEXMzMz////TjRV2AAAACXBIWXMAAArrAAAK6wGCiw1aAAAAHHRFWHRTb2Z0d2FyZQBBZG9iZSBGaXJld29ya3MgQ1M26LyyjAAAABFJREFUCJlj+M/AgBVhF/0PAH6/D/HkDxOGAAAAAElFTkSuQmCC");
181}
182
183.crop-choose {
184 overflow: hidden;
185 position: absolute;
186 top: 9px;
187 left: 100px;
188}
189#crop-input {
190 width: 1px;
191 position: relative;
192 left: -1px;
193 opacity: 0.01;
194}
195
196.crop-btn {
197 font-size: 13px;
198 padding: 6px 15px;
199 background: rgb(0, 60, 255);
200 border-radius: 2px;
201 color: white;
202 display: inline-block;
203 cursor: pointer;
204 border-radius: 2px;
205}
206.crop-btn-crop {
207 background: red;
208}
209.thumb {
210 max-width: 100%;
211 max-height: 100%;
212}
213.close {
214 display: inline-block;
215 position: absolute;
216 right: 10px;
217 top: 10px;
218 cursor: pointer;
219}
220</style>