cropper.vue 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254
  1. <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. <script>
  40. import WeCropper from './weCropper.js';
  41. export default {
  42. props: {
  43. // 裁剪矩形框的样式,其中可包含的属性为lineWidth-边框宽度(单位rpx),color: 边框颜色,
  44. // mask-遮罩颜色,一般设置为一个rgba的透明度,如"rgba(0, 0, 0, 0.35)"
  45. boundStyle: {
  46. type: Object,
  47. default() {
  48. return {
  49. lineWidth: 4,
  50. borderColor: 'rgb(245, 245, 245)',
  51. mask: 'rgba(0, 0, 0, 0.35)'
  52. };
  53. }
  54. }
  55. },
  56. data() {
  57. return {
  58. // 底部导航的高度
  59. bottomNavHeight: 50,
  60. originWidth: 200,
  61. width: 0,
  62. height: 0,
  63. cropperOpt: {
  64. id: 'cropper',
  65. targetId: 'targetCropper',
  66. pixelRatio: 1,
  67. width: 0,
  68. height: 0,
  69. scale: 2.5,
  70. zoom: 8,
  71. cut: {
  72. x: (this.width - this.originWidth) / 2,
  73. y: (this.height - this.originWidth) / 2,
  74. width: this.originWidth,
  75. height: this.originWidth
  76. },
  77. boundStyle: {
  78. lineWidth: uni.upx2px(this.boundStyle.lineWidth),
  79. mask: this.boundStyle.mask,
  80. color: this.boundStyle.borderColor
  81. }
  82. },
  83. // 裁剪框和输出图片的尺寸,高度默认等于宽度
  84. // 输出图片宽度,单位px
  85. destWidth: 200,
  86. // 裁剪框宽度,单位px
  87. rectWidth: 200,
  88. // 输出的图片类型,如果'png'类型发现裁剪的图片太大,改成"jpg"即可
  89. fileType: 'jpg',
  90. src: '' // 选择的图片路径,用于在点击确定时,判断是否选择了图片
  91. };
  92. },
  93. onLoad(option) {
  94. let rectInfo = uni.getSystemInfoSync();
  95. this.width = rectInfo.windowWidth;
  96. this.height = rectInfo.windowHeight - this.bottomNavHeight;
  97. this.cropperOpt.width = this.width;
  98. this.cropperOpt.height = this.height;
  99. this.cropperOpt.pixelRatio = rectInfo.pixelRatio;
  100. if (option.destWidth) this.destWidth = option.destWidth;
  101. if (option.rectWidth) {
  102. let rectWidth = Number(option.rectWidth);
  103. this.cropperOpt.cut = {
  104. x: (this.width - rectWidth) / 2,
  105. y: (this.height - rectWidth) / 2,
  106. width: rectWidth,
  107. height: rectWidth
  108. };
  109. }
  110. this.rectWidth = option.rectWidth;
  111. if (option.fileType) this.fileType = option.fileType;
  112. // 初始化
  113. this.cropper = new WeCropper(this.cropperOpt)
  114. .on('ready', ctx => {
  115. // wecropper is ready for work!
  116. })
  117. .on('beforeImageLoad', ctx => {
  118. // before picture loaded, i can do something
  119. })
  120. .on('imageLoad', ctx => {
  121. // picture loaded
  122. })
  123. .on('beforeDraw', (ctx, instance) => {
  124. // before canvas draw,i can do something
  125. });
  126. // 设置导航栏样式,以免用户在page.json中没有设置为黑色背景
  127. uni.setNavigationBarColor({
  128. frontColor: '#ffffff',
  129. backgroundColor: '#000000'
  130. });
  131. uni.chooseImage({
  132. count: 1, // 默认9
  133. sizeType: ['compressed'], // 可以指定是原图还是压缩图,默认二者都有
  134. sourceType: [option.source], // 可以指定来源是相册还是相机,默认二者都有
  135. success: res => {
  136. this.src = res.tempFilePaths[0];
  137. // 获取裁剪图片资源后,给data添加src属性及其值
  138. this.cropper.pushOrign(this.src);
  139. }
  140. });
  141. },
  142. methods: {
  143. touchStart(e) {
  144. this.cropper.touchStart(e);
  145. },
  146. touchMove(e) {
  147. this.cropper.touchMove(e);
  148. },
  149. touchEnd(e) {
  150. this.cropper.touchEnd(e);
  151. },
  152. getCropperImage(isPre = false) {
  153. if (!this.src) return this.$u.toast('请先选择图片再裁剪');
  154. let cropper_opt = {
  155. destHeight: Number(this.destWidth), // uni.canvasToTempFilePath要求这些参数为数值
  156. destWidth: Number(this.destWidth),
  157. fileType: this.fileType
  158. };
  159. this.cropper.getCropperImage(cropper_opt, (path, err) => {
  160. if (err) {
  161. uni.showModal({
  162. title: '温馨提示',
  163. content: err.message
  164. });
  165. } else {
  166. if (isPre) {
  167. uni.previewImage({
  168. current: '', // 当前显示图片的 http 链接
  169. urls: [path] // 需要预览的图片 http 链接列表
  170. });
  171. } else {
  172. uni.$emit('cropper', path);
  173. uni.navigateBack();
  174. }
  175. }
  176. });
  177. },
  178. uploadTap() {
  179. const self = this;
  180. uni.chooseImage({
  181. count: 1, // 默认9
  182. sizeType: ['original', 'compressed'], // 可以指定是原图还是压缩图,默认二者都有
  183. sourceType: ['album', 'camera'], // 可以指定来源是相册还是相机,默认二者都有
  184. success: res => {
  185. self.src = res.tempFilePaths[0];
  186. // 获取裁剪图片资源后,给data添加src属性及其值
  187. self.cropper.pushOrign(this.src);
  188. }
  189. });
  190. }
  191. }
  192. };
  193. </script>
  194. <style scoped lang="scss">
  195. .content {
  196. background: rgba(255, 255, 255, 1);
  197. }
  198. .cropper {
  199. position: absolute;
  200. top: 0;
  201. left: 0;
  202. width: 100%;
  203. height: 100%;
  204. z-index: 11;
  205. }
  206. .cropper-buttons {
  207. background-color: #000000;
  208. color: #eee;
  209. }
  210. .cropper-wrapper {
  211. position: relative;
  212. display: flex;
  213. flex-direction: row;
  214. justify-content: space-between;
  215. align-items: center;
  216. width: 100%;
  217. background-color: #000;
  218. }
  219. .cropper-buttons {
  220. width: 100vw;
  221. display: flex;
  222. flex-direction: row;
  223. justify-content: space-between;
  224. align-items: center;
  225. position: fixed;
  226. bottom: 0;
  227. left: 0;
  228. font-size: 28rpx;
  229. }
  230. .cropper-buttons .upload,
  231. .cropper-buttons .getCropperImage {
  232. width: 50%;
  233. text-align: center;
  234. cursor: pointer;
  235. }
  236. .cropper-buttons .upload {
  237. text-align: left;
  238. padding-left: 50rpx;
  239. }
  240. .cropper-buttons .getCropperImage {
  241. text-align: right;
  242. padding-right: 50rpx;
  243. }
  244. </style>