当前位置:   article > 正文

vue uni-app 裁剪图片(裁剪头像)插件vue-image-cropper_uni-image-cropper

uni-image-cropper

一、项目预览。

效果:

一个手指拖动,可以移动图片,两个手指拖动可以缩放。

下载该项目:

git clone https://github.com/Q956164483/vue-image-cropper.git

运行:

npm i

cd vue-image-cropper

npm run serve

二、应用在自己的项目。

1.复制“vue-image-cropper”项目中的 ./src/components/imageCropper.vue文件 (imageCropper.vue需要引入exif-small.js)

2.在需要使用的页面直接引入imageCropper组件,并绑定cropperConfig配置参数和裁剪之后的回调函数callback。

3.安装lrz。

npm i lrz -S

<image-cropper ref="imageCropper" :cropperConfig="cropperConfig" :callback="loadImage"></image-cropper>
  1. cropperConfig: {
  2. width: 1, // 裁剪宽度(比例)
  3. height: 1, // 裁剪高度(比例)
  4. quality: 0.7, // 图片质量(0~1之间)
  5. maxWidth: 750 // 导出的图片的最大宽度
  6. }

  1. loadImage (data) {
  2. console.log(data);//data为图片base64字符串,可以直接放入img的src
  3. }

三、本人修改了部分代码,可以直接复制源码。

可以选择支持一下博主,花个几十积分,我的代码:

uni-app的图片裁剪nice-cropper.rar_uniapp图片裁剪,uniapp图片裁剪-互联网文档类资源-CSDN下载

如果饭都吃不起,就选择如下:

安装lrz:

npm i lrz -S

1.效果。

2.imageCropper.vue的代码:

  1. <template>
  2. <div ref="cropperPage" class="cropper-page" v-show="isShow">
  3. <div @click="cancel()" class="icon icon-back"></div>
  4. <input ref="file" type="file" accept="image/*" @change="readImage">
  5. <img alt="" class="cropper-img" :style="imageStyle" ref="img">
  6. <div class="cover box box-ac box-jc" :style="{height: coverHeight + 'px'}">
  7. <!-- 请调整图片 -->
  8. </div>
  9. <div ref="cropBox" class="cropper-box" @touchstart.prevent="touchStart" @touchmove.prevent="touchMove"></div>
  10. <div class="cover cover box box-ac box-jc" :style="{height: coverHeight + 'px'}">
  11. <div class="box box-f1 box-jc box-fh">
  12. <div class="btn" @click="cancel">取消</div>
  13. <!--重选checkPhoto-->
  14. </div>
  15. <div class="box box-f1 box-jc box-fh">
  16. <div class="btn sure" @click="confirm">确定</div>
  17. </div>
  18. </div>
  19. </div>
  20. </template>
  21. <script>
  22. import lrz from 'lrz'
  23. const getDinstance = function(point0, point1) {
  24. return Math.sqrt(Math.pow(point0.pageY - point1.pageY, 2) + Math.pow(point0.pageX - point1.pageX, 2))
  25. }
  26. export default {
  27. name: 'imageCropper',
  28. props: {
  29. //裁剪确认后的回调,结果是图片数据。
  30. callback: {
  31. type: Function,
  32. default () {}
  33. },
  34. cropperConfig: {
  35. type: Object,
  36. default () {
  37. return {
  38. width: 1,//裁剪宽度(比例)
  39. height: 1,//裁剪高度(比例)
  40. quality: 0.7,//图片质量(0~1之间)
  41. maxWidth: 640//导出的图片最大宽度
  42. }
  43. }
  44. }
  45. },
  46. data() {
  47. return {
  48. coverHeight: 0,
  49. cropperHeight: 0,
  50. imgInitTop: 0,
  51. amplitude: 0,
  52. imageState: {
  53. left: 0,
  54. top: 0,
  55. scale: 1,
  56. width: 0,
  57. height: 0,
  58. originX: 0,
  59. originY: 0
  60. },
  61. distance: 0,
  62. imageStyle: {
  63. top: '0',
  64. transform: 'translate3d(0px, 0px, 0px) scale(1)',
  65. transformOrigin: 'left top'
  66. },
  67. cropBoxRect: {},
  68. touchPos: {
  69. x: 0,
  70. y: 0
  71. },
  72. isShow: false,
  73. minScale: 0,
  74. info: '',
  75. orientation: ''
  76. }
  77. },
  78. watch: {
  79. 'imageState': {
  80. handler(val) {
  81. this.imageStyle.transform = 'translate3d(-' + val.left + 'px, -' + val.top + 'px, 0px) scale(' + val.scale + ')'
  82. },
  83. deep: true
  84. }
  85. },
  86. methods: {
  87. cancel() {
  88. this.file = null
  89. this.isShow = false
  90. },
  91. checkPhoto() {
  92. this.$refs.file.click()
  93. },
  94. readImage($event) {
  95. var self = this
  96. var file = $event.target.files[0]
  97. lrz(file)
  98. .then(rst => {
  99. self.orientation = 1
  100. self.$refs.img.onload = () => {
  101. self.initCropper()
  102. }
  103. self.$refs.img.src = rst.base64
  104. $event.target.value = null
  105. })
  106. },
  107. initCropper() {
  108. this.isShow = true // 显示裁剪界面
  109. this.$nextTick(() => {
  110. let cropperPage = this.$refs.cropperPage
  111. let pageWidth = cropperPage.clientWidth
  112. let pageHeight = cropperPage.clientHeight
  113. let cropBox = this.$refs.cropBox
  114. let cropBoxWidth = cropBox.clientWidth
  115. let cropBoxHeight = Math.floor(cropBoxWidth * (+this.cropperConfig.height) / (+this.cropperConfig.width))
  116. this.$refs.cropBox.style.height = cropBoxHeight + 'px'
  117. this.coverHeight = (pageHeight - cropBoxHeight) / 2
  118. let cropBoxTop = this.coverHeight
  119. this.imageState.left = 0
  120. this.imageState.top = 0
  121. this.imageStyle.top = cropBoxTop + 'px'
  122. this.cropBoxRect = {
  123. left: 0,
  124. top: cropBoxTop,
  125. width: pageWidth,
  126. height: cropBoxHeight
  127. }
  128. let img = this.$refs.img
  129. var width = this.imageState.width = img.naturalWidth
  130. var height = this.imageState.height = img.naturalHeight
  131. // 计算imageState
  132. if (width > height) {
  133. this.minScale = this.imageState.scale = this.cropBoxRect.height / height
  134. this.imageState.left = (width * this.imageState.scale - this.cropBoxRect.width) / 2
  135. } else {
  136. this.minScale = this.imageState.scale = this.cropBoxRect.width / width
  137. this.imageState.top = (height * this.imageState.scale - this.cropBoxRect.height) / 2
  138. }
  139. })
  140. },
  141. confirm() {
  142. let self = this
  143. let imageState = this.imageState
  144. let cropBoxRect = this.cropBoxRect
  145. // 导出图片的最大宽度
  146. let maxWidth = this.cropperConfig.maxWidth
  147. let scale2 = maxWidth / cropBoxRect.width
  148. let scale = imageState.scale * scale2
  149. let width = cropBoxRect.width * scale2
  150. let height = cropBoxRect.height * scale2
  151. let left = imageState.left * scale2
  152. let top = imageState.top * scale2
  153. let image = this.$refs.img
  154. let canvas = document.createElement('canvas')
  155. let ctx = canvas.getContext('2d')
  156. // ios 的照片有拍摄的角度信息 参考 http://www.bcty365.com/content-142-3055-1.html
  157. let orientation = this.orientation
  158. switch (orientation) {
  159. case 1:
  160. canvas.width = width
  161. canvas.height = height
  162. ctx.drawImage(image, left / scale, top / scale, width / scale, height / scale, 0, 0, width, height)
  163. break
  164. case 6:
  165. canvas.width = height
  166. canvas.height = width
  167. ctx.rotate(90 * Math.PI / 180)
  168. ctx.drawImage(image, left / scale, top / scale, width / scale, height / scale, 0, -height, width, height)
  169. break
  170. case 8:
  171. canvas.width = height
  172. canvas.height = width
  173. ctx.rotate(-90 * Math.PI / 180)
  174. ctx.drawImage(image, left / scale, top / scale, width / scale, height / scale, -width, 0, width, height)
  175. break
  176. case 3:
  177. canvas.width = width
  178. canvas.height = height
  179. ctx.rotate(180 * Math.PI / 180)
  180. ctx.drawImage(image, left / scale, top / scale, width / scale, height / scale, -width, -height, width, height)
  181. break
  182. }
  183. let dataUrl = canvas.toDataURL('image/jpeg', this.cropperConfig.quality)
  184. self.callback(dataUrl)
  185. self.isShow = false
  186. },
  187. getFocalPoint(point0, point1) {
  188. return {
  189. x: (point0.pageX + point1.pageX) / 2,
  190. y: (point0.pageY + point1.pageY) / 2
  191. }
  192. },
  193. touchStart(event) {
  194. var fingerCount = event.touches.length
  195. if (fingerCount) {
  196. // 记录触摸初始位置
  197. let touchEvent = event.touches[0]
  198. this.touchPos = {
  199. x: touchEvent.clientX,
  200. y: touchEvent.clientY
  201. }
  202. }
  203. if (fingerCount >= 2) {
  204. // 获取两点距离、中点位置;两点距离old/new=放大倍数;中点位置,缩放中心;
  205. let point0 = event.touches[0]
  206. let point1 = event.touches[1]
  207. this.distance = getDinstance(point0, point1)
  208. this.touchPos = this.getFocalPoint(point0, point1)
  209. // 设置缩放倍数,
  210. }
  211. },
  212. touchMove(event) {
  213. // 根据触摸点位移,移动图片,重置触摸点位置
  214. var fingerCount = event.touches.length
  215. var touchEvent = event.touches[0]
  216. if (fingerCount === 1) {
  217. let distX = touchEvent.pageX - this.touchPos.x
  218. let distY = touchEvent.pageY - this.touchPos.y
  219. let newX = this.imageState.left - distX
  220. let newY = this.imageState.top - distY
  221. let scale = this.imageState.scale
  222. // alert(scale)
  223. let maxX = this.imageState.width * scale - this.cropBoxRect.width
  224. let maxY = this.imageState.height * scale - this.cropBoxRect.height
  225. this.imageState.left = newX < 0 ? 0 : (newX > maxX ? maxX : newX)
  226. this.imageState.top = newY < 0 ? 0 : (newY > maxY ? maxY : newY)
  227. this.touchPos.x = touchEvent.pageX
  228. this.touchPos.y = touchEvent.pageY
  229. } else if (fingerCount > 1) {
  230. let point0 = event.touches[0]
  231. let point1 = event.touches[1]
  232. let distance = getDinstance(point0, point1)
  233. let zoom = distance / this.distance
  234. let scale = zoom * this.imageState.scale
  235. let maxX = this.imageState.width * scale - this.cropBoxRect.width
  236. let maxY = this.imageState.height * scale - this.cropBoxRect.height
  237. let touchPos = this.getFocalPoint(point0, point1)
  238. let newX = zoom * (this.imageState.left + touchPos.x) - touchPos.x
  239. let newY = zoom * ((this.imageState.top - this.imgInitTop) + touchPos.y) - touchPos.y + this.imgInitTop
  240. // 限制缩放
  241. // 图片新位置:由中点位置确认;(新位置到中点)/(旧位置到中点)=(new scale)/(old scale)
  242. // newLeft - touchPos.x = (distance / this.distance) * (oldLetf - touchPos.x)
  243. // oldLeft = 0 - this.imageState.left
  244. // oldTop = imgInitTop - this.imageState.top
  245. this.distance = distance
  246. if (scale < this.minScale) {
  247. this.imageState.scale = this.minScale
  248. } else {
  249. this.imageState.scale = scale
  250. this.imageState.left = newX < 0 ? 0 : (newX > maxX ? maxX : newX)
  251. this.imageState.top = newY < 0 ? 0 : (newY > maxY ? maxY : newY)
  252. }
  253. this.touchPos = touchPos
  254. }
  255. }
  256. }
  257. }
  258. </script>
  259. <style lang="scss" scoped>
  260. $themeColor:#409EFF;
  261. .box {
  262. display: flex;
  263. position: relative;
  264. }
  265. .box-f1 {
  266. flex: 1;
  267. }
  268. .box-ac {
  269. align-items: center
  270. }
  271. .box-jc {
  272. justify-content: center
  273. }
  274. .box-ver {
  275. flex-direction: column
  276. }
  277. .cropper-page {
  278. position: fixed;
  279. top: 0;
  280. left: 0;
  281. width: 100%;
  282. height: 100%;
  283. z-index: 10;
  284. background-color: #fff;
  285. overflow: hidden;
  286. }
  287. .cover {
  288. color: #FFF;
  289. font-size: .4rem;
  290. background-color: rgba(0, 0, 0, 0.2);
  291. }
  292. .cropper-box {
  293. // border: 1px dashed #FFF;
  294. border: 2px dashed #FFF;
  295. }
  296. .cropper-img {
  297. position: absolute;
  298. z-index: -1;
  299. }
  300. input[type="file"] {
  301. opacity: 0;
  302. position: fixed;
  303. top: -1000px;
  304. left: -1000px;
  305. }
  306. .btn {
  307. font-size: .6rem;
  308. padding: .1rem .3rem;
  309. border: .02rem solid;
  310. color: #FFF;
  311. border-radius: .4rem;
  312. width:80px;
  313. height:35px;
  314. display: flex;
  315. align-items: center;
  316. justify-content: center;
  317. background:#909399;
  318. &.sure {
  319. background: $themeColor;
  320. }
  321. }
  322. </style>

3.简单使用。

  1. <template>
  2. <div>
  3. <image-cropper ref="imageCropper" :cropperConfig="cropperConfig" :callback="loadImage"></image-cropper>
  4. <button @click="selectFile()">打开</button>
  5. <div>
  6. <img v-if="img" :src="img" style="width:200px;height:200px;"/>
  7. </div>
  8. </div>
  9. </template>
  10. <script>
  11. import imageCropper from '@/components/imageCropper'
  12. export default {
  13. name: 'Home',
  14. components: {imageCropper},
  15. data() {
  16. return {
  17. img:'',
  18. cropperConfig: {
  19. width: 1,
  20. height: 1,
  21. quality: 0.7,
  22. maxWidth: 750
  23. }
  24. };
  25. },
  26. mounted() {
  27. },
  28. methods: {
  29. selectFile () {
  30. this.$refs.imageCropper.checkPhoto()
  31. },
  32. // 图片裁剪之后的回调
  33. loadImage (data) {
  34. // this.images.push(data)
  35. console.log(data)
  36. this.img=data;
  37. },
  38. },
  39. };
  40. </script>
  41. <style lang="scss" scoped>
  42. </style>

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/菜鸟追梦旅行/article/detail/287091
推荐阅读
相关标签
  

闽ICP备14008679号