mirror of
				https://github.com/pure-admin/vue-pure-admin.git
				synced 2025-11-03 13:44:47 +08:00 
			
		
		
		
	feat: add cropper components
This commit is contained in:
		
							parent
							
								
									ba6e3447a7
								
							
						
					
					
						commit
						90b2ac8599
					
				
							
								
								
									
										5
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										5
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							@ -562,6 +562,11 @@
 | 
				
			|||||||
      "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.10.0.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.10.0.tgz",
 | 
				
			||||||
      "integrity": "sha512-CC582enhrFZStO4F8lGI7QL3SYx7/AIRc+IdSi3btrQGrVsTawo5K/crmKbRrQ+MOMhNX4v+PATn0k2NN6wI7A=="
 | 
					      "integrity": "sha512-CC582enhrFZStO4F8lGI7QL3SYx7/AIRc+IdSi3btrQGrVsTawo5K/crmKbRrQ+MOMhNX4v+PATn0k2NN6wI7A=="
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    "cropperjs": {
 | 
				
			||||||
 | 
					      "version": "1.5.11",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/cropperjs/-/cropperjs-1.5.11.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-SJUeBBhtNBnnn+UrLKluhFRIXLJn7XFPv8QN1j49X5t+BIMwkgvDev541f96bmu8Xe0TgCx3gON22KmY/VddaA=="
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    "cssesc": {
 | 
					    "cssesc": {
 | 
				
			||||||
      "version": "3.0.0",
 | 
					      "version": "3.0.0",
 | 
				
			||||||
      "resolved": "http://192.168.250.101:4873/cssesc/-/cssesc-3.0.0.tgz",
 | 
					      "resolved": "http://192.168.250.101:4873/cssesc/-/cssesc-3.0.0.tgz",
 | 
				
			||||||
 | 
				
			|||||||
@ -11,6 +11,7 @@
 | 
				
			|||||||
    "@vueuse/core": "^4.8.1",
 | 
					    "@vueuse/core": "^4.8.1",
 | 
				
			||||||
    "await-to-js": "^2.1.1",
 | 
					    "await-to-js": "^2.1.1",
 | 
				
			||||||
    "axios": "^0.21.1",
 | 
					    "axios": "^0.21.1",
 | 
				
			||||||
 | 
					    "cropperjs": "^1.5.11",
 | 
				
			||||||
    "dayjs": "^1.10.4",
 | 
					    "dayjs": "^1.10.4",
 | 
				
			||||||
    "dotenv": "^8.2.0",
 | 
					    "dotenv": "^8.2.0",
 | 
				
			||||||
    "echarts": "^5.0.2",
 | 
					    "echarts": "^5.0.2",
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										128
									
								
								src/components/cropper/index.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										128
									
								
								src/components/cropper/index.vue
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,128 @@
 | 
				
			|||||||
 | 
					<template>
 | 
				
			||||||
 | 
					  <div :class="$attrs.class" :style="getWrapperStyle">
 | 
				
			||||||
 | 
					    <img
 | 
				
			||||||
 | 
					      v-show="isReady"
 | 
				
			||||||
 | 
					      ref="imgElRef"
 | 
				
			||||||
 | 
					      :src="src"
 | 
				
			||||||
 | 
					      :alt="alt"
 | 
				
			||||||
 | 
					      :crossorigin="crossorigin"
 | 
				
			||||||
 | 
					      :style="getImageStyle"
 | 
				
			||||||
 | 
					    />
 | 
				
			||||||
 | 
					  </div>
 | 
				
			||||||
 | 
					</template>
 | 
				
			||||||
 | 
					<script lang="ts">
 | 
				
			||||||
 | 
					  import type { CSSProperties } from 'vue';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  import { defineComponent, onMounted, ref, unref, computed, PropType } from 'vue';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  import Cropper from 'cropperjs';
 | 
				
			||||||
 | 
					  import 'cropperjs/dist/cropper.css';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  type Options = Cropper.Options;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const defaultOptions: Cropper.Options = {
 | 
				
			||||||
 | 
					    aspectRatio: 16 / 9,
 | 
				
			||||||
 | 
					    zoomable: true,
 | 
				
			||||||
 | 
					    zoomOnTouch: true,
 | 
				
			||||||
 | 
					    zoomOnWheel: true,
 | 
				
			||||||
 | 
					    cropBoxMovable: true,
 | 
				
			||||||
 | 
					    cropBoxResizable: true,
 | 
				
			||||||
 | 
					    toggleDragModeOnDblclick: true,
 | 
				
			||||||
 | 
					    autoCrop: true,
 | 
				
			||||||
 | 
					    background: true,
 | 
				
			||||||
 | 
					    highlight: true,
 | 
				
			||||||
 | 
					    center: true,
 | 
				
			||||||
 | 
					    responsive: true,
 | 
				
			||||||
 | 
					    restore: true,
 | 
				
			||||||
 | 
					    checkCrossOrigin: true,
 | 
				
			||||||
 | 
					    checkOrientation: true,
 | 
				
			||||||
 | 
					    scalable: true,
 | 
				
			||||||
 | 
					    modal: true,
 | 
				
			||||||
 | 
					    guides: true,
 | 
				
			||||||
 | 
					    movable: true,
 | 
				
			||||||
 | 
					    rotatable: true,
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					  export default defineComponent({
 | 
				
			||||||
 | 
					    props: {
 | 
				
			||||||
 | 
					      src: {
 | 
				
			||||||
 | 
					        type: String,
 | 
				
			||||||
 | 
					        required: true,
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      alt: {
 | 
				
			||||||
 | 
					        type: String,
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      height: {
 | 
				
			||||||
 | 
					        type: [String, Number],
 | 
				
			||||||
 | 
					        default: '360px',
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      crossorigin: {
 | 
				
			||||||
 | 
					        type: String,
 | 
				
			||||||
 | 
					        default: undefined,
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      imageStyle: {
 | 
				
			||||||
 | 
					        type: Object as PropType<CSSProperties>,
 | 
				
			||||||
 | 
					        default: {},
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      options: {
 | 
				
			||||||
 | 
					        type: Object as PropType<Options>,
 | 
				
			||||||
 | 
					        default: {},
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    setup(props, ctx) {
 | 
				
			||||||
 | 
					      const imgElRef = ref<ElRef<HTMLImageElement>>(null);
 | 
				
			||||||
 | 
					      const cropper: any = ref<Nullable<Cropper>>(null);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      const isReady = ref(false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      const getImageStyle = computed(
 | 
				
			||||||
 | 
					        (): CSSProperties => {
 | 
				
			||||||
 | 
					          return {
 | 
				
			||||||
 | 
					            height: props.height,
 | 
				
			||||||
 | 
					            maxWidth: '100%',
 | 
				
			||||||
 | 
					            ...props.imageStyle,
 | 
				
			||||||
 | 
					          };
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      const getWrapperStyle = computed(
 | 
				
			||||||
 | 
					        (): CSSProperties => {
 | 
				
			||||||
 | 
					          const { height } = props;
 | 
				
			||||||
 | 
					          return { height: `${height}`.replace(/px/, '') + 'px' };
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      async function init() {
 | 
				
			||||||
 | 
					        const imgEl = unref(imgElRef);
 | 
				
			||||||
 | 
					        if (!imgEl) {
 | 
				
			||||||
 | 
					          return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        cropper.value = new Cropper(imgEl, {
 | 
				
			||||||
 | 
					          ...defaultOptions,
 | 
				
			||||||
 | 
					          ready: () => {
 | 
				
			||||||
 | 
					            isReady.value = true;
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          ...props.options,
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      // event: return base64 and width and height information after cropping
 | 
				
			||||||
 | 
					      const croppered = (): void => {
 | 
				
			||||||
 | 
					        let imgInfo = cropper.value.getData();
 | 
				
			||||||
 | 
					        cropper.value.getCroppedCanvas().toBlob(blob => {
 | 
				
			||||||
 | 
					        let fileReader: FileReader = new FileReader()
 | 
				
			||||||
 | 
					          fileReader.onloadend = (e: any) => {
 | 
				
			||||||
 | 
					            ctx.emit("cropperedInfo", {
 | 
				
			||||||
 | 
					              imgBase64: e.target.result,
 | 
				
			||||||
 | 
					              imgInfo
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					          fileReader.readAsDataURL(blob)
 | 
				
			||||||
 | 
					        }, 'image/jpeg')
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      onMounted(init);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      return { imgElRef, getWrapperStyle, getImageStyle, isReady, croppered };
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					</script>
 | 
				
			||||||
@ -14,5 +14,6 @@
 | 
				
			|||||||
  "map": "地图组件",
 | 
					  "map": "地图组件",
 | 
				
			||||||
  "draggable": "拖拽组件",
 | 
					  "draggable": "拖拽组件",
 | 
				
			||||||
  "split-pane": "切割面板",
 | 
					  "split-pane": "切割面板",
 | 
				
			||||||
  "button": "按钮组件"
 | 
					  "button": "按钮组件",
 | 
				
			||||||
 | 
					  "cropping": "图片裁剪"
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -14,5 +14,6 @@
 | 
				
			|||||||
  "map": "Map Components",
 | 
					  "map": "Map Components",
 | 
				
			||||||
  "draggable": "Draggable Components",
 | 
					  "draggable": "Draggable Components",
 | 
				
			||||||
  "split-pane": "Split Pane",
 | 
					  "split-pane": "Split Pane",
 | 
				
			||||||
  "button": "Button Components"
 | 
					  "button": "Button Components",
 | 
				
			||||||
 | 
					  "cropping": "Picture Cropping"
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -76,6 +76,15 @@ const routes: Array<RouteRecordRaw> = [
 | 
				
			|||||||
          showLink: false,
 | 
					          showLink: false,
 | 
				
			||||||
          savedPosition: true
 | 
					          savedPosition: true
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        path: '/components/cropping',
 | 
				
			||||||
 | 
					        component: () => import(/* webpackChunkName: "components" */ '../views/components/cropping/index.vue'),
 | 
				
			||||||
 | 
					        meta: {
 | 
				
			||||||
 | 
					          title: 'cropping',
 | 
				
			||||||
 | 
					          showLink: false,
 | 
				
			||||||
 | 
					          savedPosition: true
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    ],
 | 
					    ],
 | 
				
			||||||
    meta: {
 | 
					    meta: {
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										62
									
								
								src/views/components/cropping/index.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										62
									
								
								src/views/components/cropping/index.vue
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,62 @@
 | 
				
			|||||||
 | 
					<template>
 | 
				
			||||||
 | 
					  <div style="margin: 10px">
 | 
				
			||||||
 | 
					    <div class="cropper-container">
 | 
				
			||||||
 | 
					      <cropperImage ref="refCropper" :src="img" @cropperedInfo="cropperedInfo" style="width:45%" />
 | 
				
			||||||
 | 
					      <img :src="cropperImg" class="croppered" v-if="cropperImg" />
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					    <el-button type="primary" @click="onCropper">裁剪</el-button>
 | 
				
			||||||
 | 
					    <p v-if="cropperImg">裁剪后图片信息:{{ info }}</p>
 | 
				
			||||||
 | 
					  </div>
 | 
				
			||||||
 | 
					</template>
 | 
				
			||||||
 | 
					<script lang="ts">
 | 
				
			||||||
 | 
					import { defineComponent, ref, onBeforeMount, getCurrentInstance } from "vue";
 | 
				
			||||||
 | 
					import cropperImage from "../../../components/cropper/index.vue";
 | 
				
			||||||
 | 
					import img from "./picture.jpeg";
 | 
				
			||||||
 | 
					export default defineComponent({
 | 
				
			||||||
 | 
					  components: {
 | 
				
			||||||
 | 
					    cropperImage
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  setup() {
 | 
				
			||||||
 | 
					    let vm: any;
 | 
				
			||||||
 | 
					    let info = ref("");
 | 
				
			||||||
 | 
					    let cropperImg = ref("");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const onCropper = (): void => {
 | 
				
			||||||
 | 
					      vm.refs.refCropper.croppered();
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    onBeforeMount(() => {
 | 
				
			||||||
 | 
					      vm = getCurrentInstance();
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function cropperedInfo({ imgBase64, imgInfo }) {
 | 
				
			||||||
 | 
					      info.value = imgInfo;
 | 
				
			||||||
 | 
					      cropperImg.value = imgBase64;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return {
 | 
				
			||||||
 | 
					      img,
 | 
				
			||||||
 | 
					      info,
 | 
				
			||||||
 | 
					      cropperImg,
 | 
				
			||||||
 | 
					      onCropper,
 | 
				
			||||||
 | 
					      cropperedInfo
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<style scoped>
 | 
				
			||||||
 | 
					.cropper-container {
 | 
				
			||||||
 | 
					  display: flex;
 | 
				
			||||||
 | 
					  justify-content: space-between;
 | 
				
			||||||
 | 
					  align-items: center;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					.el-button {
 | 
				
			||||||
 | 
					  margin-top: 10px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					.croppered {
 | 
				
			||||||
 | 
					  display: block;
 | 
				
			||||||
 | 
					  width: 45%;
 | 
				
			||||||
 | 
					  height: 360px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					</style>
 | 
				
			||||||
							
								
								
									
										
											BIN
										
									
								
								src/views/components/cropping/picture.jpeg
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								src/views/components/cropping/picture.jpeg
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 23 KiB  | 
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user