How to Create a Cropper Component in Vue Using TypeScript and vue-advanced-cropper
Table of contents
Using a pre-defined cropper such as Vue-advanced-cropper can save you a lot of time, but using it properly as a reusable component is not always easy to implement. In this tutorial, you will learn how to create a cropper component in Vue using TypeScript and the vue-advanced-cropper library.
Getting Started
First, you need to install the Vue-advanced-cropper library. You can do this by running the following command in your terminal:
npm install vue-advanced-cropper
Once the library is installed, is time to create our reusable component. You can do this by creating a new file called BaseCropper.vue
The code
The following code shows the basic structure of the BaseCropper.vue
component:
<script lang="ts" setup>
import { Cropper } from 'vue-advanced-cropper'
import 'vue-advanced-cropper/dist/style.css'
import { ref, watch } from 'vue'
defineProps({
imageSource: {
type: String,
required: true,
},
imageSize: {
type: Object,
},
})
const imageRef = ref('parentImageRef')
const emit = defineEmits(['onImageChange', 'onCrop', 'onCancel'])
watch(imageRef, () => {
emit('onImageChange', imageRef.value)
})
</script>
<template>
<div>
<Cropper
ref="imageRef"
:src="imageSource"
:stencil-size="imageSize"
:stencil-props="{
handlers: {},
movable: false,
resizable: false,
}"
image-restriction="stencil"
/>
<hr class="solid" >
<div>
<button @click="$emit('onCancel')">Cancel</button>
<button @click="$emit('onCrop')">Crop image</button>
</div>
</div>
</template>
<style>
.cropper {
min-height: 300px;
width: 100%;
}
hr.solid {
border-top: 3px solid #bbb;
}
</style>
The template for the Cropper
component is simple. It simply renders the Cropper
component with the imageSource and imageSize props. It also renders a hr element and two buttons. The first button is used to cancel the crop, and the second button is used to crop the image.
Piece by piece
Now will let's explain the complete code piece by piece
<script lang="ts" setup>
import { Cropper } from 'vue-advanced-cropper'
import 'vue-advanced-cropper/dist/style.css'
import { ref, watch } from 'vue'
// Define the props
defineProps({
imageSource: {
type: String,
required: true,
},
imageSize: {
type: Object,
},
})
// Create a ref to the image
const imageRef = ref('parentImageRef')
// Define the emits
const emit = defineEmits(['onImageChange', 'onCrop', 'onCancel'])
// Watch the imageRef and emit the onImageChange event when it changes
watch(imageRef, () => {
emit('onImageChange', imageRef.value)
})
</script>
The first part of the code imports the Cropper
component from the vue-advanced-cropper
library. It also imports the CSS styles for the Cropper
component. Then, it defines the props for the Cropper
component. There are just two props that I consider necessary in my component but there are a lot of possible props, you can explore the library API to define those you could add.
The imageSource
prop is required and is the URL of the image that you want to crop. The imageSize
prop is an object that specifies the width and height of the image.
Next, the code creates a ref to the image. This ref will be used to access the image in the template. Then, let's define the emits for the Cropper
component.
The onImageChange
event is emitted when the image changes (This will be used by the parent component to update its ref). The onCrop
event is emitted when the crop is complete, and the onCancel
event is emitted when the user cancels the crop.
Finally, the code watches the image and emits the onImageChange
event when it changes. This ensures that the image is always up-to-date.
<template>
<div>
<Cropper
ref="imageRef"
:src="imageSource"
:stencil-size="imageSize"
:stencil-props="{
handlers: {},
movable: false,
resizable: false,
}"
image-restriction="stencil"
/>
<hr class="solid" >
<div>
<button @click="$emit('onCancel')">Cancel</button>
<button @click="$emit('onCrop')">Crop image</button>
</div>
</div>
</template>
<style>
.cropper {
min-height: 300px;
width: 100%;
}
hr.solid {
border-top: 3px solid #bbb;
}
</style>
The CSS styles for the Cropper
component are very simple. They simply set the min-height and width of the Cropper
component to 300px and 100%, respectively.
Using the component
Once the component is created, we can use it.
In this example, I'm using it in a custom dialog component after a file was selected
<BaseDialog v-model="coverDialog">
<ImageCropper
:image-source="coverPicked"
:image-size="{
width: 500,
height: 200,
}"
@on-crop="cropCoverImage"
@on-cancel="closeCoverDialog"
@on-image-change="updateCoverRef"
/>
</BaseDialog>
And the result is:
Conclusion
This is a basic example of how to create a Cropper Vue component using TypeScript and Vue-advanced-cropper. You can use this code as a starting point to create your own Cropper component.