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",
 | 
			
		||||
      "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": {
 | 
			
		||||
      "version": "3.0.0",
 | 
			
		||||
      "resolved": "http://192.168.250.101:4873/cssesc/-/cssesc-3.0.0.tgz",
 | 
			
		||||
 | 
			
		||||
@ -11,6 +11,7 @@
 | 
			
		||||
    "@vueuse/core": "^4.8.1",
 | 
			
		||||
    "await-to-js": "^2.1.1",
 | 
			
		||||
    "axios": "^0.21.1",
 | 
			
		||||
    "cropperjs": "^1.5.11",
 | 
			
		||||
    "dayjs": "^1.10.4",
 | 
			
		||||
    "dotenv": "^8.2.0",
 | 
			
		||||
    "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": "地图组件",
 | 
			
		||||
  "draggable": "拖拽组件",
 | 
			
		||||
  "split-pane": "切割面板",
 | 
			
		||||
  "button": "按钮组件"
 | 
			
		||||
  "button": "按钮组件",
 | 
			
		||||
  "cropping": "图片裁剪"
 | 
			
		||||
}
 | 
			
		||||
@ -14,5 +14,6 @@
 | 
			
		||||
  "map": "Map Components",
 | 
			
		||||
  "draggable": "Draggable Components",
 | 
			
		||||
  "split-pane": "Split Pane",
 | 
			
		||||
  "button": "Button Components"
 | 
			
		||||
  "button": "Button Components",
 | 
			
		||||
  "cropping": "Picture Cropping"
 | 
			
		||||
}
 | 
			
		||||
@ -76,6 +76,15 @@ const routes: Array<RouteRecordRaw> = [
 | 
			
		||||
          showLink: false,
 | 
			
		||||
          savedPosition: true
 | 
			
		||||
        }
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        path: '/components/cropping',
 | 
			
		||||
        component: () => import(/* webpackChunkName: "components" */ '../views/components/cropping/index.vue'),
 | 
			
		||||
        meta: {
 | 
			
		||||
          title: 'cropping',
 | 
			
		||||
          showLink: false,
 | 
			
		||||
          savedPosition: true
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    ],
 | 
			
		||||
    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