index.vue 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  1. <script lang="ts" setup>
  2. import 'vue-cropper/dist/index.css'
  3. import { VueCropper } from 'vue-cropper'
  4. import {ref,defineEmits} from "vue"
  5. import api from '@/api'
  6. import {ElMessage} from "element-plus";
  7. interface Props{
  8. imgUrl: string;
  9. imgName:string;
  10. }
  11. const props = withDefaults(defineProps<Props>(),{
  12. imgUrl:'',
  13. imgName:''
  14. })
  15. const emit = defineEmits(['uploadImg']);
  16. const cropper = ref<InstanceType<typeof VueCropper>>()
  17. const inputRef = ref<HTMLInputElement>()
  18. const loading = ref<boolean>(false)
  19. const isReady = ref<boolean>(false)
  20. // vue-cropper的基本配置
  21. // console.log(props.imgUrl,666)
  22. const option = ref({
  23. img: props.imgUrl, //裁剪图片的地址
  24. outputSize: 1, //裁剪生成图片的质量(可选0.1 - 1)
  25. outputType: 'jpeg', //裁剪生成图片的格式(jpeg || png || webp)
  26. info: true, //图片大小信息
  27. canScale: true, //图片是否允许滚轮缩放
  28. autoCrop: true, //是否默认生成截图框
  29. autoCropWidth: 150, //默认生成截图框宽度
  30. autoCropHeight: 150, //默认生成截图框高度
  31. fixed: true, //是否开启截图框宽高固定比例
  32. fixedNumber: [1, 1], //截图框的宽高比例
  33. full: false, //false按原比例裁切图片,不失真
  34. fixedBox: false, //固定截图框大小,不允许改变
  35. canMove: false, //上传图片是否可以移动
  36. canMoveBox: true, //截图框能否拖动
  37. original: false, //上传图片按照原始比例渲染
  38. centerBox: false, //截图框是否被限制在图片里面
  39. height: true, //是否按照设备的dpr 输出等比例图片
  40. infoTrue: false, //true为展示真实输出图片宽高,false展示看到的截图框宽高
  41. maxImgSize: 3000, //限制图片最大宽度和高度
  42. enlarge: 1, //图片根据截图框输出比例倍数
  43. mode: '300px 300px' //图片默认渲染方式
  44. })
  45. const previewURL = ref<string>('')
  46. // 实时的刷新
  47. const realTime = () => {
  48. if (loading.value) return
  49. loading.value = true
  50. // 节流
  51. setTimeout(() => {
  52. cropper.value.getCropBlob((data: Blob) => {
  53. previewURL.value = URL.createObjectURL(data)
  54. console.log(previewURL.value)
  55. loading.value = false
  56. })
  57. }, 500)
  58. }
  59. // 初始化
  60. const imgLoad = (msg: string) => {
  61. if (msg === 'success') {
  62. isReady.value = true
  63. }
  64. }
  65. //选择图片
  66. const img=ref()
  67. const selectImg = (e: Event) => {
  68. const eTarget = e.target as HTMLInputElement
  69. if (!eTarget.files) return
  70. const file = eTarget.files[0]
  71. if (!/\.(jpg|jpeg|png|JPG|PNG)$/.test(eTarget.value)) {
  72. alert('图片格式错误')
  73. return false
  74. }
  75. img.value=file
  76. // console.log(file)
  77. const reader = new FileReader()
  78. reader.readAsDataURL(file) //将文件转化为base64
  79. reader.onload = e => {
  80. let data
  81. if (!e.target) return
  82. if (typeof e.target.result === 'object') {
  83. data = URL.createObjectURL(new Blob([e.target.result ?? '']))
  84. } else {
  85. data = e.target.result
  86. }
  87. option.value.img = data
  88. }
  89. }
  90. //图片缩放
  91. const changeScale = (num: number) => {
  92. num = num || 1
  93. cropper.value.changeScale(num)
  94. }
  95. //向左旋转
  96. const rotateLeft = () => {
  97. cropper.value.rotateLeft()
  98. }
  99. //向右旋转
  100. const rotateRight = () => {
  101. cropper.value.rotateRight()
  102. }
  103. //上传图片
  104. const imgUpload = () => {
  105. //获取截图的blob数据
  106. // console.log(cropper.value)
  107. // console.log(cropper.value.scaleImg)
  108. cropper.value.getCropBlob(async (data: File) => {
  109. let formData = new FormData();
  110. const files = new File([data],img.value?.name || props.imgName,{
  111. type:data.type
  112. }); // 声明formData数据类型
  113. formData.append('file',files)
  114. // console.log(img.value.size)
  115. // console.log(data)
  116. // params.append("file", );
  117. api.areaApi.fileUpload(formData).then((res: any) => {
  118. if (res.code === 200) {
  119. // console.log(res)
  120. ElMessage({
  121. message: '上传成功',
  122. type: 'success'
  123. })
  124. emit("uploadImg", res.data);
  125. } else {
  126. ElMessage({
  127. message: res.msg,
  128. type: 'warning'
  129. })
  130. }
  131. });
  132. // 上传到服务器
  133. })
  134. }
  135. //选择图片
  136. const selectClick = () => {
  137. inputRef.value?.click()
  138. }
  139. </script>
  140. <template>
  141. <div class="h-[40vh] w-[100vw] ">
  142. <div class="w-[800px] h-[300px]">
  143. <div class="w-[800px] h-[300px] flex items-center justify-between">
  144. <!-- 给组件固定宽高 -->
  145. <div class="h-[300px] w-[510px]" style="width: 500px">
  146. <VueCropper
  147. ref="cropper"
  148. :img="option.img"
  149. :outputSize="option.outputSize"
  150. :outputType="option.outputType"
  151. :info="option.info"
  152. :canScale="option.canScale"
  153. :autoCrop="option.autoCrop"
  154. :autoCropWidth="option.autoCropWidth"
  155. :autoCropHeight="option.autoCropHeight"
  156. :fixed="option.fixed"
  157. :fixedNumber="option.fixedNumber"
  158. :full="option.full"
  159. :fixedBox="option.fixedBox"
  160. :canMove="option.canMove"
  161. :canMoveBox="option.canMoveBox"
  162. :original="option.original"
  163. :centerBox="option.centerBox"
  164. :height="option.height"
  165. :infoTrue="option.infoTrue"
  166. :maxImgSize="option.maxImgSize"
  167. :enlarge="option.enlarge"
  168. :mode="option.mode"
  169. @realTime="realTime"
  170. @imgLoad="imgLoad"
  171. ></VueCropper>
  172. </div>
  173. <!-- <div class="ml-[60px]">
  174. <div class="text-center text-[#409EFF] mb-[20px] text-[20px] font-medium">预览</div>
  175. <div class="flex items-center">
  176. <div v-if="isReady">
  177. <el-image class="rounded-[50%] w-[150px] h-[150px]" :src="previewURL" />
  178. </div>
  179. </div>
  180. </div> -->
  181. </div>
  182. <div class="flex items-center mt-[30px]">
  183. <div class="relative">
  184. <div
  185. class="mr-[15px] cursor-pointer text-[20px] text-[#409EFF] font-semibold"
  186. @click="selectClick"
  187. >
  188. 选择图片
  189. </div>
  190. <input
  191. ref="inputRef"
  192. type="file"
  193. style="position: absolute; clip: rect(0 0 0 0)"
  194. accept="image/png, image/jpeg, image/gif, image/jpg"
  195. @change="selectImg"
  196. />
  197. </div>
  198. <el-button style="width: 96px" type="primary" @click="changeScale(1)">放大</el-button>
  199. <el-button style="width: 96px" type="primary" @click="changeScale(-1)">缩小</el-button>
  200. <el-button style="width: 96px" type="primary" @click="rotateLeft">↺ 左旋转</el-button>
  201. <el-button style="width: 96px" type="primary" @click="rotateRight">↻ 右旋转</el-button>
  202. <el-button type="primary" plain @click="imgUpload">上传图片</el-button>
  203. </div>
  204. </div>
  205. </div>
  206. </template>
  207. <style scoped lang="scss"></style>