cropper.vue 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. <template>
  2. <div>
  3. <Confirm :title="title" :func="clickHandler" :noText="noText" :okText="okText">
  4. <template #content>
  5. <div>
  6. <div class="cropper-layer" :style="style">
  7. <VueCropper v-if="show" ref="vmRef" v-bind="option" v-on="on" />
  8. </div>
  9. <div class="size" v-if="showSize">
  10. <ui-input :label="`Logo-${longSize}`" type="radio" name="size" :modelValue="sizeType == 1" @update:modelValue="changSize(1)" />
  11. <ui-input :label="`Logo-${squareSize}`" type="radio" name="size" :modelValue="sizeType == 2" @update:modelValue="changSize(2)" />
  12. </div>
  13. </div>
  14. </template>
  15. </Confirm>
  16. </div>
  17. </template>
  18. <script setup lang="ts">
  19. import { VueCropper } from 'vue-cropper'
  20. import Confirm from '../dialog/confirm.vue'
  21. import { computed, defineProps, ref, nextTick } from 'vue'
  22. import 'vue-cropper/dist/index.css'
  23. // import { useI18n } from '@/i18n'
  24. // const { t } = useI18n({ useScope: 'global' })
  25. const sizeType = ref(1)
  26. const layerWidth = 500
  27. const props = defineProps({
  28. fixedNumber: {
  29. type: Array,
  30. default: () => [1, 1],
  31. },
  32. img: { type: String },
  33. cb: {
  34. type: Function,
  35. },
  36. showSize: {
  37. type: Boolean,
  38. default: false,
  39. },
  40. noText: {
  41. type: String,
  42. default: '取消',
  43. },
  44. okText: {
  45. type: String,
  46. default: '确认',
  47. },
  48. title: {
  49. type: String,
  50. default: '裁剪',
  51. },
  52. longSize: {
  53. type: String,
  54. default: '长型',
  55. },
  56. squareSize: {
  57. type: String,
  58. default: '方型',
  59. },
  60. })
  61. const show = ref(true)
  62. // const fixedNumber = props.fixedNumber
  63. const getHeight = width => (fixedNumber[1] / fixedNumber[0]) * width
  64. const option = {
  65. outputSize: 1,
  66. outputType: 'png',
  67. info: false,
  68. full: true,
  69. fixed: true,
  70. canScale: true,
  71. fixedNumber: props.fixedNumber,
  72. canMove: true,
  73. canMoveBox: true,
  74. fixedBox: false,
  75. original: false,
  76. autoCrop: true,
  77. autoCropWidth: layerWidth / 2,
  78. autoCropHeight: getHeight(layerWidth / 2),
  79. centerBox: false,
  80. mode: 'contain',
  81. maxImgSize: 400,
  82. // ...props,
  83. }
  84. const changSize = type => {
  85. if (sizeType.value != type) {
  86. sizeType.value = type
  87. show.value = false
  88. if (type == 1) {
  89. option.fixedNumber = [2, 1]
  90. } else {
  91. option.fixedNumber = [1, 1]
  92. }
  93. nextTick(() => {
  94. show.value = true
  95. })
  96. }
  97. }
  98. const style = computed(() => ({
  99. width: layerWidth + 'px',
  100. height: getHeight(layerWidth) + 'px',
  101. }))
  102. const vmRef = ref()
  103. const on = {
  104. imgLoad(status) {
  105. if (status !== 'success') {
  106. props.cb('图片加载失败')
  107. }
  108. },
  109. }
  110. const clickHandler = async status => {
  111. if (status === 'ok') {
  112. let data = await Promise.all([new Promise(resolve => vmRef.value.getCropBlob(resolve)), new Promise(resolve => vmRef.value.getCropData(resolve))])
  113. if (props.showSize) {
  114. data.push(sizeType.value)
  115. }
  116. props.cb(null, data)
  117. } else {
  118. props.cb()
  119. }
  120. }
  121. </script>
  122. <script>
  123. export default { name: 'UiCropper' }
  124. </script>
  125. <style lang="scss">
  126. .vue-cropper {
  127. background-repeat: repeat;
  128. }
  129. .cropper-view-box {
  130. outline-color: var(--color-main-normal) !important;
  131. }
  132. .crop-point {
  133. background-color: var(--color-main-normal) !important;
  134. }
  135. .size {
  136. width: 100%;
  137. display: flex;
  138. align-items: center;
  139. justify-content: center;
  140. margin-top: 20px;
  141. }
  142. .ui-input {
  143. margin-right: 30px;
  144. &:last-of-type {
  145. margin-right: 0;
  146. }
  147. }
  148. </style>