blob: a48dd546434c653d8b1645a2cc1840a6fe72a230 [file] [log] [blame]
guangchao.xu070005a2020-12-07 09:56:40 +08001<template>
2 <view class="content">
3 <view class="cropper-wrapper" :style="{ height: cropperOpt.height + 'px' }">
4 <canvas
5 class="cropper"
6 :disable-scroll="true"
7 @touchstart="touchStart"
8 @touchmove="touchMove"
9 @touchend="touchEnd"
10 :style="{ width: cropperOpt.width, height: cropperOpt.height, backgroundColor: 'rgba(0, 0, 0, 0.8)' }"
11 canvas-id="cropper"
12 id="cropper"
13 ></canvas>
14 <canvas
15 class="cropper"
16 :disable-scroll="true"
17 :style="{
18 position: 'fixed',
19 top: `-${cropperOpt.width * cropperOpt.pixelRatio}px`,
20 left: `-${cropperOpt.height * cropperOpt.pixelRatio}px`,
21 width: `${cropperOpt.width * cropperOpt.pixelRatio}px`,
22 height: `${cropperOpt.height * cropperOpt.pixelRatio}`
23 }"
24 canvas-id="targetId"
25 id="targetId"
26 ></canvas>
27 </view>
28 <view class="cropper-buttons safe-area-padding" :style="{ height: bottomNavHeight + 'px' }">
29 <!-- #ifdef H5 -->
30 <view class="upload" @tap="uploadTap">选择图片</view>
31 <!-- #endif -->
32 <!-- #ifndef H5 -->
33 <view class="upload" @tap="uploadTap">重新选择</view>
34 <!-- #endif -->
35 <view class="getCropperImage" @tap="getCropperImage(false)">确定</view>
36 </view>
37 </view>
38</template>
39
40<script>
41import WeCropper from './weCropper.js';
42export default {
43 props: {
44 // 裁剪矩形框的样式,其中可包含的属性为lineWidth-边框宽度(单位rpx),color: 边框颜色,
45 // mask-遮罩颜色,一般设置为一个rgba的透明度,如"rgba(0, 0, 0, 0.35)"
46 boundStyle: {
47 type: Object,
48 default() {
49 return {
50 lineWidth: 4,
51 borderColor: 'rgb(245, 245, 245)',
52 mask: 'rgba(0, 0, 0, 0.35)'
53 };
54 }
55 }
56 // // 裁剪框宽度,单位rpx
57 // rectWidth: {
58 // type: [String, Number],
59 // default: 400
60 // },
61 // // 裁剪框高度,单位rpx
62 // rectHeight: {
63 // type: [String, Number],
64 // default: 400
65 // },
66 // // 输出图片宽度,单位rpx
67 // destWidth: {
68 // type: [String, Number],
69 // default: 400
70 // },
71 // // 输出图片高度,单位rpx
72 // destHeight: {
73 // type: [String, Number],
74 // default: 400
75 // },
76 // // 输出的图片类型,如果发现裁剪的图片很大,可能是因为设置为了"png",改成"jpg"即可
77 // fileType: {
78 // type: String,
79 // default: 'jpg',
80 // },
81 // // 生成的图片质量
82 // // H5上无效,目前不考虑使用此参数
83 // quality: {
84 // type: [Number, String],
85 // default: 1
86 // }
87 },
88 data() {
89 return {
90 // 底部导航的高度
91 bottomNavHeight: 50,
92 originWidth: 200,
93 width: 0,
94 height: 0,
95 cropperOpt: {
96 id: 'cropper',
97 targetId: 'targetCropper',
98 pixelRatio: 1,
99 width: 0,
100 height: 0,
101 scale: 2.5,
102 zoom: 8,
103 cut: {
104 x: (this.width - this.originWidth) / 2,
105 y: (this.height - this.originWidth) / 2,
106 width: this.originWidth,
107 height: this.originWidth
108 },
109 boundStyle: {
110 lineWidth: uni.upx2px(this.boundStyle.lineWidth),
111 mask: this.boundStyle.mask,
112 color: this.boundStyle.borderColor
113 }
114 },
115 // 裁剪框和输出图片的尺寸,高度默认等于宽度
116 // 输出图片宽度,单位px
117 destWidth: 200,
118 // 裁剪框宽度,单位px
119 rectWidth: 200,
120 // 输出的图片类型,如果'png'类型发现裁剪的图片太大,改成"jpg"即可
121 fileType: 'jpg',
122 src: '', // 选择的图片路径,用于在点击确定时,判断是否选择了图片
123 };
124 },
125 onLoad(option) {
126 let rectInfo = uni.getSystemInfoSync();
127 this.width = rectInfo.windowWidth;
128 this.height = rectInfo.windowHeight - this.bottomNavHeight;
129 this.cropperOpt.width = this.width;
130 this.cropperOpt.height = this.height;
131 this.cropperOpt.pixelRatio = rectInfo.pixelRatio;
132
133 if (option.destWidth) this.destWidth = option.destWidth;
134 if (option.rectWidth) {
135 let rectWidth = Number(option.rectWidth);
136 this.cropperOpt.cut = {
137 x: (this.width - rectWidth) / 2,
138 y: (this.height - rectWidth) / 2,
139 width: rectWidth,
140 height: rectWidth
141 };
142 }
143 this.rectWidth = option.rectWidth;
144 if (option.fileType) this.fileType = option.fileType;
145 // 初始化
146 this.cropper = new WeCropper(this.cropperOpt)
147 .on('ready', ctx => {
148 // wecropper is ready for work!
149 })
150 .on('beforeImageLoad', ctx => {
151 // before picture loaded, i can do something
152 })
153 .on('imageLoad', ctx => {
154 // picture loaded
155 })
156 .on('beforeDraw', (ctx, instance) => {
157 // before canvas draw,i can do something
158 });
159 // 设置导航栏样式,以免用户在page.json中没有设置为黑色背景
160 uni.setNavigationBarColor({
161 frontColor: '#ffffff',
162 backgroundColor: '#000000'
163 });
164 uni.chooseImage({
165 count: 1, // 默认9
166 sizeType: ['compressed'], // 可以指定是原图还是压缩图,默认二者都有
167 sourceType: ['album', 'camera'], // 可以指定来源是相册还是相机,默认二者都有
168 success: res => {
169 this.src = res.tempFilePaths[0];
170 // 获取裁剪图片资源后,给data添加src属性及其值
171 this.cropper.pushOrign(this.src);
172 }
173 });
174 },
175 methods: {
176 touchStart(e) {
177 this.cropper.touchStart(e);
178 },
179 touchMove(e) {
180 this.cropper.touchMove(e);
181 },
182 touchEnd(e) {
183 this.cropper.touchEnd(e);
184 },
185 getCropperImage(isPre = false) {
186 if(!this.src) return this.$u.toast('请先选择图片再裁剪');
187
188 let cropper_opt = {
189 destHeight: Number(this.destWidth), // uni.canvasToTempFilePath要求这些参数为数值
190 destWidth: Number(this.destWidth),
191 fileType: this.fileType
192 };
193 this.cropper.getCropperImage(cropper_opt, (path, err) => {
194 if (err) {
195 uni.showModal({
196 title: '温馨提示',
197 content: err.message
198 });
199 } else {
200 if (isPre) {
201 uni.previewImage({
202 current: '', // 当前显示图片的 http 链接
203 urls: [path] // 需要预览的图片 http 链接列表
204 });
205 } else {
206 uni.$emit('uAvatarCropper', path);
207 this.$u.route({
208 type: 'back'
209 });
210 }
211 }
212 });
213 },
214 uploadTap() {
215 const self = this;
216 uni.chooseImage({
217 count: 1, // 默认9
218 sizeType: ['original', 'compressed'], // 可以指定是原图还是压缩图,默认二者都有
219 sourceType: ['album', 'camera'], // 可以指定来源是相册还是相机,默认二者都有
220 success: (res) => {
221 self.src = res.tempFilePaths[0];
222 // 获取裁剪图片资源后,给data添加src属性及其值
223
224 self.cropper.pushOrign(this.src);
225 }
226 });
227 }
228 }
229};
230</script>
231
232<style scoped lang="scss">
233@import '../../libs/css/style.components.scss';
234
235.content {
236 background: rgba(255, 255, 255, 1);
237}
238
239.cropper {
240 position: absolute;
241 top: 0;
242 left: 0;
243 width: 100%;
244 height: 100%;
245 z-index: 11;
246}
247
248.cropper-buttons {
249 background-color: #000000;
250 color: #eee;
251}
252
253.cropper-wrapper {
254 position: relative;
255 @include vue-flex;
256 flex-direction: row;
257 justify-content: space-between;
258 align-items: center;
259 width: 100%;
260 background-color: #000;
261}
262
263.cropper-buttons {
264 width: 100vw;
265 @include vue-flex;
266 flex-direction: row;
267 justify-content: space-between;
268 align-items: center;
269 position: fixed;
270 bottom: 0;
271 left: 0;
272 font-size: 28rpx;
273}
274
275.cropper-buttons .upload,
276.cropper-buttons .getCropperImage {
277 width: 50%;
278 text-align: center;
279}
280
281.cropper-buttons .upload {
282 text-align: left;
283 padding-left: 50rpx;
284}
285
286.cropper-buttons .getCropperImage {
287 text-align: right;
288 padding-right: 50rpx;
289}
290</style>