cropper.vue 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  1. <template>
  2. <div class="cropper-box">
  3. <!-- <VueCropper v-if="show" ref="vmRef" v-bind="option" v-on="on" /> -->
  4. <div class="layout">
  5. <p class="title">{{ title }}</p>
  6. <div class="content">
  7. <VueCropper v-if="show" ref="vmRef" v-bind="option" v-on="on" />
  8. </div>
  9. <div class="footer">
  10. <div class="cancel" @click="cancelCrop()">{{ noText }}</div>
  11. <div class="confirm" @click="confirmCrop()">{{ okText }}</div>
  12. </div>
  13. </div>
  14. </div>
  15. </template>
  16. <script setup>
  17. import { VueCropper } from 'vue-cropper';
  18. import 'vue-cropper/dist/index.css';
  19. import { computed, defineProps, ref, nextTick, defineEmits } from 'vue';
  20. // import 'vue-cropper/dist/index.css'
  21. // import { useI18n } from '@/i18n'
  22. // const { t } = useI18n({ useScope: 'global' })
  23. const sizeType = ref(1);
  24. const layerWidth = 256;
  25. const emit = defineEmits(['close', 'ok']);
  26. const props = defineProps({
  27. fixedNumber: {
  28. type: Array,
  29. default: () => [1, 1],
  30. },
  31. img: { type: String },
  32. noText: {
  33. type: String,
  34. default: '取消',
  35. },
  36. okText: {
  37. type: String,
  38. default: '确认',
  39. },
  40. title: {
  41. type: String,
  42. default: '裁剪',
  43. },
  44. });
  45. const show = ref(true);
  46. const fixedNumber = props.fixedNumber;
  47. const getHeight = (width) => (fixedNumber[1] / fixedNumber[0]) * width;
  48. const option = {
  49. outputSize: 1,
  50. outputType: 'png',
  51. info: false,
  52. full: true,
  53. fixed: true,
  54. canScale: true,
  55. fixedNumber: fixedNumber,
  56. canMove: true,
  57. canMoveBox: true,
  58. fixedBox: false,
  59. original: false,
  60. autoCrop: true,
  61. autoCropWidth: layerWidth / 2,
  62. autoCropHeight: getHeight(layerWidth / 2),
  63. centerBox: false,
  64. mode: 'contain',
  65. maxImgSize: 400,
  66. ...props,
  67. };
  68. const vmRef = ref(null);
  69. const on = {
  70. imgLoad(status) {
  71. if (status !== 'success') {
  72. // props.cb('图片加载失败');
  73. }
  74. },
  75. };
  76. const clickHandler = async (status) => {
  77. if (status === 'ok') {
  78. let data = await Promise.all([new Promise((resolve) => vmRef.value.getCropBlob(resolve)), new Promise((resolve) => vmRef.value.getCropData(resolve))]);
  79. if (props.showSize) {
  80. data.push(sizeType.value);
  81. }
  82. props.cb(null, data);
  83. } else {
  84. props.cb();
  85. }
  86. };
  87. const confirmCrop = () => {
  88. vmRef.value.getCropData((data) => {
  89. // do something
  90. emit('ok', data);
  91. emit('close');
  92. });
  93. };
  94. const cancelCrop = () => {
  95. emit('close');
  96. };
  97. </script>
  98. <style lang="scss" socped>
  99. .vue-cropper {
  100. background-repeat: repeat;
  101. }
  102. .cropper-box {
  103. width: 100%;
  104. height: 100%;
  105. position: fixed;
  106. top: 0;
  107. left: 0;
  108. background: rgba(0, 0, 0, 0.6);
  109. .layout {
  110. width: 8.64rem;
  111. min-height: 5rem;
  112. // background: #ffffff;
  113. pointer-events: auto;
  114. position: absolute;
  115. left: 50%;
  116. top: 50%;
  117. transform: translate(-50%, -50%);
  118. // overflow: hidden;
  119. border: 1px solid rgba(255, 255, 255, 0.1);
  120. border-radius: 4px;
  121. background: rgba(0, 0, 0, 0.7);
  122. .title {
  123. font-size: 0.39rem;
  124. width: 100%;
  125. height: 1.39rem;
  126. padding: 0 0.56rem;
  127. box-sizing: border-box;
  128. font-size: 0.39rem;
  129. color: #fff;
  130. line-height: 1.39rem;
  131. overflow: hidden;
  132. text-overflow: ellipsis;
  133. white-space: nowrap;
  134. border-bottom-style: solid;
  135. border-bottom-width: 1px;
  136. border-bottom-color: rgba(255, 255, 255, 0.1);
  137. }
  138. .content {
  139. width: 100%;
  140. height: 3.4133rem;
  141. margin: 0.56rem 0;
  142. }
  143. .footer {
  144. width: 100%;
  145. height: 1.36rem;
  146. border-top-style: solid;
  147. border-top-width: 1px;
  148. border-top-color: rgba(255, 255, 255, 0.1);
  149. box-sizing: border-box;
  150. display: flex;
  151. align-items: center;
  152. justify-content: center;
  153. font-size: 0.39rem;
  154. > div {
  155. width: 50%;
  156. height: 1.36rem;
  157. text-align: center;
  158. line-height: 1.36rem;
  159. font-size: 0.39rem;
  160. box-sizing: border-box;
  161. &.cancel {
  162. color: #fff;
  163. border-right-style: solid;
  164. border-right-width: 1px;
  165. border-right-color: rgba(255, 255, 255, 0.1);
  166. }
  167. &.confirm {
  168. color: #ed5d18;
  169. }
  170. }
  171. }
  172. }
  173. }
  174. </style>
  175. <style lang="scss">
  176. .cropper-view-box {
  177. outline-color: var(--color-main-normal) !important;
  178. }
  179. .crop-point {
  180. background-color: var(--color-main-normal) !important;
  181. }
  182. .size {
  183. width: 100%;
  184. display: flex;
  185. align-items: center;
  186. justify-content: center;
  187. margin-top: 20px;
  188. }
  189. </style>
  190. <script>
  191. export default { name: 'ui-cropper' };
  192. </script>