基于 vue 图片裁剪(vue-cropper)
# 安装
npm install vue-cropper --save
1
# 使用
main.js里面
import VueCropper from 'vue-cropper'
Vue.use(VueCropper)
1
2
2
或者组件里
<script>
import { VueCropper } from "vue-cropper";
export default {
name: "CropperImage",
components: {
VueCropper,
}
};
</script>
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
# 示例代码
<template>
<Modal
v-model="isOpen"
class-name="cropper-image-modal"
@on-visible-change="handleVisibleChange"
width="50%"
>
<div slot="header" class="header">
<h2>
<span><Icon type="md-cut" size="12"/></span> <span>图片裁剪</span>
</h2>
</div>
<div class="cropper-content">
<div class="cropper-box">
<div class="cropper">
<vue-cropper
ref="cropper"
:img="option.img"
:outputSize="option.outputSize"
:outputType="option.outputType"
:info="option.info"
:canScale="option.canScale"
:autoCrop="option.autoCrop"
:autoCropWidth="option.autoCropWidth"
:autoCropHeight="option.autoCropHeight"
:fixed="option.fixed"
:fixedNumber="option.fixedNumber"
:full="option.full"
:fixedBox="option.fixedBox"
:canMove="option.canMove"
:canMoveBox="option.canMoveBox"
:original="option.original"
:centerBox="option.centerBox"
:height="option.height"
:infoTrue="option.infoTrue"
:maxImgSize="option.maxImgSize"
:enlarge="option.enlarge"
:mode="option.mode"
@realTime="realTime"
@imgLoad="imgLoad"
>
</vue-cropper>
</div>
<!--底部操作工具按钮-->
<div class="footer-btn">
<div class="scope-btn">
<label class="btn" for="uploads">选择封面</label>
<input
type="file"
id="uploads"
style="position: absolute; clip: rect(0 0 0 0)"
accept="image/png, image/jpeg, image/gif, image/jpg"
@change="selectImg($event)"
/>
<Button @click="changeScale(1)">放大</Button>
<Button @click="changeScale(-1)">缩小</Button>
<Button @click="rotateLeft">↺ 左旋转</Button>
<Button @click="rotateRight">↻ 右旋转</Button>
</div>
<div class="upload-btn">
<Button type="success" @click="uploadImg('blob')"
>上传封面 <i class="el-icon-upload"></i
></Button>
</div>
</div>
</div>
<!--预览效果图-->
<div class="show-preview">
<div :style="previews.div" class="preview">
<img :src="previews.url" :style="previews.img" />
</div>
</div>
</div>
</Modal>
</template>
<script>
import { VueCropper } from "vue-cropper";
export default {
name: "CropperImage",
components: {
VueCropper,
},
// props: ["Name"],
data() {
return {
isOpen: true,
name: "",
previews: {},
option: {
img: "", //裁剪图片的地址
outputSize: 1, //裁剪生成图片的质量(可选0.1 - 1)
outputType: "jpeg", //裁剪生成图片的格式(jpeg || png || webp)
info: true, //图片大小信息
canScale: true, //图片是否允许滚轮缩放
autoCrop: true, //是否默认生成截图框
autoCropWidth: 230, //默认生成截图框宽度
autoCropHeight: 150, //默认生成截图框高度
fixed: true, //是否开启截图框宽高固定比例
fixedNumber: [1.53, 1], //截图框的宽高比例
full: false, //false按原比例裁切图片,不失真
fixedBox: false, //固定截图框大小,不允许改变
canMove: false, //上传图片是否可以移动
canMoveBox: true, //截图框能否拖动
original: false, //上传图片按照原始比例渲染
centerBox: false, //截图框是否被限制在图片里面
height: true, //是否按照设备的dpr 输出等比例图片
infoTrue: false, //true为展示真实输出图片宽高,false展示看到的截图框宽高
maxImgSize: 3000, //限制图片最大宽度和高度
enlarge: 1, //图片根据截图框输出比例倍数
mode: "230px 150px", //图片默认渲染方式
},
};
},
methods: {
handleVisibleChange(value) {
if (!value) {
clearTimeout(this.time);
this.time = setTimeout(() => {
this.$parent.isAccountSet = false;
}, 500);
}
},
//初始化函数
imgLoad(msg) {
console.log("工具初始化函数=====" + msg);
},
//图片缩放
changeScale(num) {
num = num || 1;
this.$refs.cropper.changeScale(num);
},
//向左旋转
rotateLeft() {
this.$refs.cropper.rotateLeft();
},
//向右旋转
rotateRight() {
this.$refs.cropper.rotateRight();
},
//实时预览函数
realTime(data) {
this.previews = data;
},
//选择图片
selectImg(e) {
let file = e.target.files[0];
if (!/\.(jpg|jpeg|png|JPG|PNG)$/.test(e.target.value)) {
this.$message({
message: "图片类型要求:jpeg、jpg、png",
type: "error",
});
return false;
}
//转化为blob
let reader = new FileReader();
reader.onload = (e) => {
let data;
if (typeof e.target.result === "object") {
data = window.URL.createObjectURL(new Blob([e.target.result]));
} else {
data = e.target.result;
}
this.option.img = data;
};
//转化为base64
reader.readAsDataURL(file);
},
//上传图片
uploadImg(type) {
let _this = this;
if (type === "blob") {
//获取截图的blob数据
this.$refs.cropper.getCropBlob(async (data) => {
let formData = new FormData();
formData.append("file", data, "DX.jpg");
//调用axios上传
let { data: res } = await _this.$http.post("/api/file/imgUpload", formData);
if (res.code === 200) {
_this.$message({
message: res.msg,
type: "success",
});
let data = res.data.replace("[", "").replace("]", "").split(",");
let imgInfo = {
name: _this.Name,
url: data[0],
};
_this.$emit("uploadImgSuccess", imgInfo);
} else {
_this.$message({
message: "文件服务异常,请联系管理员!",
type: "error",
});
}
});
}
},
},
};
</script>
<style lang="scss">
.cropper-image-modal {
.cropper-content {
display: flex;
display: -webkit-flex;
justify-content: flex-end;
.cropper-box {
flex: 1;
width: 100%;
.cropper {
width: auto;
height: 300px;
}
}
.show-preview {
flex: 1;
-webkit-flex: 1;
display: flex;
display: -webkit-flex;
justify-content: center;
.preview {
overflow: hidden;
border: 1px solid #67c23a;
background: #cccccc;
}
}
}
.footer-btn {
margin-top: 30px;
display: flex;
display: -webkit-flex;
justify-content: flex-end;
.scope-btn {
display: flex;
display: -webkit-flex;
justify-content: space-between;
padding-right: 10px;
}
.upload-btn {
flex: 1;
-webkit-flex: 1;
display: flex;
display: -webkit-flex;
justify-content: center;
}
.btn {
outline: none;
display: inline-block;
line-height: 1;
white-space: nowrap;
cursor: pointer;
-webkit-appearance: none;
text-align: center;
-webkit-box-sizing: border-box;
box-sizing: border-box;
outline: 0;
-webkit-transition: 0.1s;
transition: 0.1s;
font-weight: 500;
padding: 8px 15px;
font-size: 12px;
border-radius: 3px;
color: #fff;
background-color: #409eff;
border-color: #409eff;
margin-right: 10px;
}
}
}
</style>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
# 示例图片
上次更新: 2024/01/30, 00:35:17
- 02
- Node与GLIBC_2.27不兼容解决方案08-19
- 03
- Git清空本地文件跟踪缓存08-13