Vue Cropper

0.6.5 · active · verified Sun Apr 19

Vue Cropper is a lightweight and easy-to-integrate image cropping component designed for Vue.js applications. The current stable version, `1.1.1`, offers comprehensive support for both Vue 2 and Vue 3, allowing developers to implement image clipping functionalities across different project generations. It is primarily distributed via npm and follows an active, though somewhat irregular, release cadence, with updates primarily focusing on compatibility and bug fixes. Key differentiators include its straightforward API for image selection, scaling, rotation, and data extraction (base64 or blob), making it a popular choice for user profile picture uploads, content creation tools, and other scenarios requiring precise image manipulation directly within the browser. Its minimalist design aims to provide essential cropping features without excessive overhead, integrating seamlessly into existing Vue ecosystems.

Common errors

Warnings

Install

Imports

Quickstart

Demonstrates basic image loading, displaying the cropper, allowing the user to select a crop area, and extracting the cropped image as a Base64 string for preview or upload, using Vue 3 Composition API with TypeScript. It also includes the necessary CSS import.

<template>
  <div class="cropper-container">
    <input type="file" accept="image/*" @change="handleFileChange" />
    <div class="cropper-wrapper" v-if="imgSrc">
      <VueCropper
        ref="cropperRef"
        :img="imgSrc"
        :output-size="outputSize"
        :output-type="outputType"
        :info="true"
        :full="true"
        :fixed-box="false"
        :can-move="true"
        :can-move-box="true"
        :original="false"
        :auto-crop="true"
        :auto-crop-width="200"
        :auto-crop-height="150"
        @realTime="realTimePreview"
      ></VueCropper>
    </div>
    <button @click="cropImage" v-if="imgSrc">Crop Image</button>
    <div class="preview" v-if="previewImg">
      <h3>Preview:</h3>
      <img :src="previewImg" alt="Cropped Image Preview" />
    </div>
  </div>
</template>

<script setup lang="ts">
import { ref, watch } from 'vue';
import VueCropper from 'vue-cropper';
import 'vue-cropper/dist/index.css'; // Don't forget to import the CSS

// Define the type for the VueCropper instance
interface VueCropperInstance {
  getCropData: (callback: (data: string) => void) => void;
  getCropBlob: (callback: (blob: Blob) => void) => void;
  // Add other methods if you plan to use them, e.g., setCropBoxData, zoom
}

const cropperRef = ref<VueCropperInstance | null>(null);
const imgSrc = ref<string | null>(null);
const previewImg = ref<string | null>(null);
const outputSize = ref(1); // Output image quality (0 to 1)
const outputType = ref('jpeg'); // Output image format (jpeg, png, webp)

const handleFileChange = (e: Event) => {
  const file = (e.target as HTMLInputElement).files?.[0];
  if (file) {
    const reader = new FileReader();
    reader.onload = (event) => {
      imgSrc.value = event.target?.result as string;
    };
    reader.readAsDataURL(file);
  }
};

const cropImage = () => {
  if (cropperRef.value) {
    cropperRef.value.getCropData((data: string) => {
      previewImg.value = data;
      console.log('Cropped Base64:', data.substring(0, 50) + '...');
      // For uploading blob:
      // cropperRef.value?.getCropBlob((blob: Blob) => {
      //   console.log('Cropped Blob:', blob);
      //   // You can upload the blob to your server here
      // });
    });
  }
};

const realTimePreview = (data: { img: string }) => {
  // Optional: Update a smaller preview in real-time as the user crops
  // For this quickstart, we'll just show the final crop on button click.
  // If you want a live preview, you can set previewImg.value = data.img here.
};

// Watch for changes in imgSrc to reset preview when a new image is selected
watch(imgSrc, () => {
  previewImg.value = null;
});
</script>

<style scoped>
.cropper-container {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 20px;
  padding: 20px;
  border: 1px solid #eee;
  border-radius: 8px;
  max-width: 600px;
  margin: 20px auto;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05);
}
.cropper-wrapper {
  width: 100%;
  max-width: 500px;
  height: 300px;
  background-color: #f8f8f8;
  border: 1px dashed #ccc;
  display: flex;
  justify-content: center;
  align-items: center;
}
.preview {
  margin-top: 20px;
  text-align: center;
}
.preview img {
  max-width: 100%;
  height: auto;
  border: 1px solid #ddd;
  border-radius: 4px;
}
input[type="file"] {
  padding: 10px;
  border: 1px solid #ccc;
  border-radius: 4px;
  cursor: pointer;
}
button {
  background-color: #42b983;
  color: white;
  border: none;
  padding: 10px 20px;
  border-radius: 4px;
  cursor: pointer;
  font-size: 16px;
  transition: background-color 0.2s ease;
}
button:hover {
  background-color: #368a6f;
}
</style>

view raw JSON →