Code Monkey home page Code Monkey logo

vue-avatar-cropper's Introduction

👧 A simple and elegant component to crop and upload avatars.

image

Edit Demo

Basic usage

<button @click="showCropper = true">Select an image</button>

<avatar-cropper
  v-model="showCropper"
  upload-url="/files/upload"
  @uploaded="handleUploaded"
/>

<script>
  export default {
    data() {
      return {
        showCropper: false,
      }
    },
    methods: {
      handleUploaded({ form, request, response }) {
        // update user avatar attribute
      },
    },
  }
</script>

Need more editing features?

Pintura the modern JavaScript Image Editor is what you're looking for.

Pintura supports setting crop aspect ratios, resizing, rotating, cropping, flipping images, and more.

Learn more about Pintura

Installing

Browsers

  1. Include the link to AvatarCropper in <head> alongside Vue.js, Cropper.js and Mime:

    <link
      rel="stylesheet"
      href="https://unpkg.com/[email protected]/dist/cropper.min.css"
    />
    <script src="https://unpkg.com/[email protected]/dist/cropper.js"></script>
    <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
    <script src="https://unpkg.com/vue-avatar-cropper/dist/avatar-cropper.umd.js"></script>
    <script src="https://wzrd.in/standalone/mime%2flite@latest"></script>
  2. Add a trigger button and <avatar-cropper> to mount the component:

<button @click="showCropper = true">Select an image</button>

<avatar-cropper
  v-model="showCropper"
  upload-url="/files/upload"
  @uploaded="handleUploaded"
/>
  1. Create Vue instance and register AvatarCropper component:
<script>
  Vue.createApp({
    el: '#app',

    data() {
      return {
        showCropper: false,
      }
    },

    methods: {
      handleUploaded(event) {
        console.log('avatar uploaded', event)
      },
    },
  })
    .use(AvatarCropper)
    .mount('#app')
</script>

Node environment

  1. Install the AvatarCropper package:

    npm install vue-avatar-cropper
    
    # or
    yarn add vue-avatar-cropper
  2. Register it as you usually would:

    import AvatarCropper from 'vue-avatar-cropper'
    
    // or
    const AvatarCropper = require('vue-avatar-cropper')
    
    Vue.component('AvatarCropper', AvatarCropper)
    
    // or
    Vue.use(AvatarCropper)
    
    // or
    new Vue({
      components: { AvatarCropper },
      // ...
    })

Props

Property Name Type Description
modelValue Boolean Set to true to show the avatar cropper, this prop is used for v-model. Default: false
file File File to use instead of prompting the user to upload one
upload-url String URL to upload the file to
upload-file-field String FormData field to use for the file. Default: 'file'
upload-file-name String/Function File name to use for the FormData field. Can be String or Function({ filename, mime, extension }) => String. Default: Automatically determined from the uploaded File's name property and the extension of the output MIME.
upload-form-data FormData Additional FormData. Default: new FormData()
upload-handler Function Handler to replace default upload handler, the argument is cropperJS instance.
request-options Object Options passed to the init parameter of the Request() constructor. Use this to set the method, headers, etc. Default: { method: 'POST' }
cropper-options Object Options passed to the cropperJS instance.
Default: {
    aspectRatio: 1,
    autoCropArea: 1,
    viewMode: 1,
    movable: false,
    zoomable: false
}
output-options Object Options passed to the cropper.getCroppedCanvas() method.
Default: {}. Recommended use-case is specifying an output size, for instance: { width: 512, height: 512 }
output-mime String The resulting avatar image MIME type, if invalid image/png will be used. Default: null
output-quality Number The resulting avatar image quality [0 - 1]. Default: 0.9
(if the output-mime property is 'image/jpeg' or 'image/webp')
mimes String Allowed image formats. Default:
'image/png, image/gif, image/jpeg, image/bmp, image/x-icon'
capture String Capture attribute for the file input. Forces mobile users to take a new picture with the back(Use value 'environment') or front(Use value 'user') camera
labels Object Label for buttons. Default: { submit: 'Ok', cancel: 'Cancel' }
inline Boolean If true component will be displayed as inline elemenet. Default: false

Events

  • update:modelValue modelValue prop changed, used for v-model, parameter:

    • value boolean.
  • changed user picked a file, parameter is an object containing:

  • submit right after a click on the submit button

  • cancel when user decides to cancel the upload

  • uploading before submit upload request, parameter is an object containing:

  • uploaded after request is successful, parameter is an object containing:

  • completed after request has completed, parameter is an object containing:

  • error something went wrong, parameter is an object containing:

    • message error message.
    • type error type, example: 'load'/'upload'/'user'.
    • context context data.

You can listen for these events like this:

<avatar-cropper
  v-model="showCropper"
  upload-url="/files/upload"
  @uploading="handleUploading"
  @uploaded="handleUploaded"
  @completed="handleCompleted"
  @error="handleError"
/>
export default {
  //...
  methods: {
    ...
    handleUploading({ form, request, response }) {
      // show a loader
    },

    handleUploaded({ form, request, response }) {
      // update user avatar attribute
    },

    handleCompleted({ form, request, response }) {
      // close the loader
    },

    handleError({ message, type, context}) {
      if (type === 'upload') {
        const { request, response } = context
      }
    }
  },
}

🚀 There is an online demo:

Edit test-project

❤️ Sponsor me

Sponsor me

如果你喜欢我的项目并想支持它,点击这里 ❤️

Project supported by JetBrains

Many thanks to Jetbrains for kindly providing a license for me to work on this and other open-source projects.

License

MIT

vue-avatar-cropper's People

Contributors

0xradical avatar aetbaev avatar dependabot-preview[bot] avatar dependabot-support avatar dependabot[bot] avatar dongsongshan avatar ferretwithaberet avatar gavrushuk avatar jalyna avatar mbardelmeijer avatar mjamro avatar mustafaaloko avatar overtrue avatar stevengbrown avatar tianyong90 avatar wmcmurray avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

vue-avatar-cropper's Issues

请问npm上版本更新的问题

用yarn安装的,版本是@0.0.14,有一个props在github这里是没有的,事实上也确实不是必须的(如果不用默认handler)而且名字和一个event名字相同,我最后看node_modules里的源码才发现这个问题...

image

所以npm上的版本不是自动和这里同步的吗?

How to handle upload on laravel

Thanks for the simple and powerful component, I just want to know how would I get the uploaded file at Laravel end. I have tried following but didn't work.

This how I used it

<avatar-cropper
                @uploaded="updateUserAvatar"
                @uploading="handleUploading"
                trigger="#pick-avatar"
                :labels="labels"
                :upload-headers="{'X-Requested-With': 'XMLHttpRequest'}"
                upload-url="/avatar">
</avatar-cropper>

Update
It seems as soon as I crop then I get the following error, but If I upload an image without cropping it works 😕

// Get the blob
$request->get('file');
// Get the file 
$request->file('file');

UploadedFile {#736
  -test: false
  -originalName: "blob"
  -mimeType: "application/octet-stream"
  -size: 0
  -error: 1
  #hashName: null
  path: ""
  filename: ""
  basename: ""
  pathname: ""
  extension: ""
  realPath: "/Volumes/connecticco/app/public"
  aTime: 1970-01-01 00:00:00
  mTime: 1970-01-01 00:00:00
  cTime: 1970-01-01 00:00:00
  inode: false
  size: false
  perms: 00
  owner: false
  group: false
  type: false
  writable: false
  readable: false
  executable: false
  file: false
  dir: false
  link: false
}

I am unable to upload it to php, please help

Check photo

How to check, the user pick a photo or not? mb some event?

Valid 201 response status raises error

The xhr callback is only checking for status 200.
I think it would be correct to consider status 201 as a valid status as well. For example an API that I am consuming for uploading files ( and implicitly creating resources) returns a successful 201.

custom upload handler

I would like to use my own method to upload the cropped image by axios instead of uploading it from the component itself, since in some cases I will want a patch and not a post, and other parameters of the call. is this possible? I can not do it

thanks in advance, I really like this component

JPG to PNG results into corrupt

Hi
When we upload JPG image (either for resizing or for cropping) we store the resulted image into .PNG file format.
We can open and access the resulted PNG image without any problem.
But internally we found resulted PNG images are having corrupt PNG Headers

'file' =>
array (size=5)
'name' => string '132.jpg' (length=7)
'type' => string 'image/png' (length=9)
'tmp_name' => string '/tmp/phpmSDIUl' (length=14)
'error' => int 0
'size' => int 105091

No avatar make trigger found

Good day,

Everytime I load the component, the "No avatar make trigger found." error triggered from the handlerError method.

<div v-for="(identity_information, index) in profile.identity_informations" :key="index"> <img v-if="identity_information.profile_picture" :src="'../../../public/' + identity_information.profile_picture" class="img-circle" width="200" height="200" id="profilePicture"> <img v-else src="../../../images/profile_picture.png" class="img-circle" width="200" height="200" id="profilePicture"> <div id="changePic"> <span><i class="fa fa-camera"></i>Change Picture</span> </div> </div> <avatar-cropper @changed="handleChanged" @uploading="handleUploading" @uploaded="handleUploaded" @completed="handleCompleted" @error="handlerError" upload-url="/api/v1/service-provider/identity-information/saveprofilepicture" trigger="#changePic" :cropper-options="{ movable: true, zoomable: true }" :labels="{ submit: 'Submit', cancel: 'Cancel' }" upload-form-name="file" :upload-form-data="{ 'file': file }" :upload-headers="{ 'Content-Type': 'multipart/form-data', 'X-Requested-With': 'XMLHttpRequest', 'Authorization': token }" />

`<script>
import axios from 'axios'
import AvatarCropper from 'vue-avatar-cropper'
import { eventHandle } from '../../globalbus'

export default {
components: {
AvatarCropper
},
data() {
return {
user_id: '',
profile: '',
file: '',
token: 'Bearer ' + window.localStorage.getItem('token'),
button: [
{
route_name: 'service-provider.profile',
title: 'Profile'
}
],
lists: [

		{
			route_name: 'service-provider.identity',
      title: 'Identity Information',
      active: false,
      mode : 0
		},
		{
    route_name: 'service-provider.medical-education',
      title: 'Medical Education',
      active: false,
      mode : 1
		},
		{
    route_name: 'service-provider.saudi',
      title: 'Saudi Commission',
      active: false,
      mode : 1
		},
		{
    route_name: 'service-provider.academic',
      title: 'Academic Teaching',
      active: false,
      mode : 1
		},

		{
    route_name: 'service-provider.withdraw-methods',
      title: 'Financial & Transactions',
      active: false,
      mode : 1
		},
		{
    route_name: 'service-provider.payment-methods',
      title: 'Withdraw Method',
      active: false,
      mode : 1
		},
		{
    route_name: 'service-provider.account-settings',
      title: 'Account Settings',
      active: false,
      mode : 1
		}
	]
}

},

methods: {
checkMode(title) {
this.activate(title)
},
getServiceProviderProfile() {
axios.get('service-provider/profile').then(response => {
this.user_id = response.data.id;
this.profile = response.data
}).catch(error => {
window.console.log(error.response)
})
},
activate(title) {

  let x = this.lists.length - 1
  while(x >= 0) {
    if (this.lists[x].title == title) {
    this.lists[x].active = true
    } else {
      this.lists[x].active = false
      }
    x -= 1
  }
},
saveProfilePicture() {
  let headers =  {
    headers: {
      'Content-Type': 'multipart/form-data',
      'X-Requested-With': 'XMLHttpRequest',
    }
  }

  let formData = new FormData()
  formData.append('file', this.profile)

  axios.post('/service-provider/identity-information/saveprofilepicture', formData, headers).then(response => {
    window.console.log('axios response', response)
    this.getServiceProviderProfile()
  }).catch(error => {
    window.console.log('saveProfilePicture error', error)
  })
},
handleChanged(file, reader) {
  window.console.log('file', file)
  window.console.log('reader', reader)
  this.file = file
},
handleUploading(form, xhr) {
  window.console.log('uploading...')
  window.console.log('form', form)
  window.console.log('xhr', xhr)
},
handleUploaded(response) {
  window.console.log('handleUploaded', response)
  if (response.status == "success") {
    // this.user.avatar = response.url;
    // Maybe you need call vuex action to
    // update user avatar, for example:
    // this.$dispatch('updateUser', {avatar: response.url})
    window.console.log('user avatar updated.')
  }
},
handleCompleted(response, form, xhr) {
  window.console.log('handleCompleted', response)
  window.console.log('handleCompleted form', form)
  window.console.log('upload completed.')
},
handlerError(message, type, xhr) {
  window.console.log('Oops! Something went wrong...')
  window.console.log('message', message)
  window.console.log('type', type)
  window.console.log('xhr', xhr)
}

},
created() {
this.getServiceProviderProfile()
}
}
</script>`

Hope you can respond right now, TIA!

Using with nuxtjs

Trying to use vue-avatar-cropper in nuxtjs project. After including it as local or global component nuxt returns an error:
image

Please advise how cropper can be correctly attached?

Example of how to use with Vuex

Hi there,

Thanks for putting together this component - looks like it will be very useful.

Would you be able to put together an example of how this component could be used with Vuex (i.e. upload to a Vuex action)?

Many thanks,

Neil

第一次使用有点不会 纠结了好久,希望超哥 帮帮忙

upload-url="/files/upload/" 写的是保存图片的路径还是接口 我写了 全部都是 404 有点小萌新
updateUserAvatar 这个写在 methods 属性里可以吗? 我连第一关都没有过~~~

POST http://localhost:3000/files/upload/ 404 (Not Found) 我也试着换过路径都是 404
(anonymous) @ index.js?96fe:1
VM19050:1 Uncaught SyntaxError: Unexpected token < in JSON at position 0
at JSON.parse ()
at XMLHttpRequest.a.onreadystatechange (index.js?96fe:1)

怎么添加请求token

在uploading事件中,怎么给请求头添加token? 使用xhr时,也不行,因为它前面要有open事件?麻烦指教一下

Entity too large error

Hello, This plugin works extremely fine but whenever i try to crop an image with a large file size, it says entity too large.

is there a way to adjust the max allowed size please?

支持上传前回调吗?

很高兴能找到你这个插件。
我的需求需要在选完图片后进行一些异步操作再附带一些数据上传图片,当前插件能够做到吗? 谢谢。急用。期望指导!

If I put two components in the VUE, another button is pressed, but the system file dialog will not pop up.

ex.

in Main.vue

first one:


<form @submit.prevent="createAward" method="POST" class="vld-parent" ref="formContainer">

                <div class="card-img-overlay has-padding-top-10 has-padding-bottom-10">
                  <b-button size="is-small" class="is-primary" id="bpick-avatar">upTest</b-button>
                </div>

              <avatar-cropper
                @uploading="handleUploading"
                @uploaded="handleUploaded"
                @completed="handleCompleted"
                @error="handlerError"
                trigger="#bpick-avatar"
                upload-url="http://lemon.test/api/upload"
              />

  </form>

another one:

<form @submit.prevent="editAward" method="POST" class="vld-parent" ref="formContainer">

                <div class="card-img-overlay has-padding-top-10 has-padding-bottom-10">
                  <b-button size="is-small" class="is-primary" id="cpick-avatar">upCTest</b-button>
                </div>

              <avatar-cropper
                @uploading="handleUploading"
                @uploaded="handleUploaded"
                @completed="handleCompleted"
                @error="handlerError"
                trigger="#cpick-avatar"
                upload-url="http://lemon.test/api/upload"
              />

      </form>

OK, upTest can click, and will be pop up the system file dialog.

BUT.....

now when I click the "upCTest" button, no any error show, and also no any response. even the system file dialog will not pop up...

pls help.....

perfect

it is a nice component ! simple but useful

上传文件后缀名命题

本以为这么常见的组件一定有很多轮子,没想到不仅稀缺还没有好用的.最终找到这个项目可用,先谢谢作者. 问题在于上传文件的filename默认为blob,都没有后缀的,如何能修改为选择文件的名字呢? 谢谢了

Upload failed when crop area is not small

I'm not able to understand the reason behind upload failure.
Is there any restriction on image size or dimension? If it is, what is the maximum size of image acceptable for this component?
Please mention the limitation regarding acceptable size and format etc...

The image I'm using is:
treetimelapse2

Use same mime output as origin

Is it possible to don't change mime type in output image, so if I choose PNG image then the output will be PNG, same for JPG etc.?

Window not defined on refresh page

Hi, i use this component in a page. When i refresh the page from browser the page does not work and show me Window not defined error in Vue-avatar-cropper component. I already tried to put the component is <client-only> tag but there is the same error.
How i can to solve this?
Thanks

获取到的数据的mime总是png

我是使用this.$refs.avatarCropper.cropper.getCroppedCanvas().toDataURL()来获取图片数据的,
但发现无论outputMime设置为什么,获取到的都是png格式的数据。

cropperAttributes: {
  trigger: '#avatarTrigger',
  cropperOptions: {
    // movable: true,
    // zoomable: true
  },
  // outputQuality: 1,
  outputMime: 'image/jpeg',
  mimes: 'image/jpeg, image/png, image/gif',
}

当trigger指向的是另一个组件时,组件运行存在异常,error事件也不触发,上传文件的对话框也不弹出

我在进行一个简单的vue单组件开发一个头像上传页面

使用Usage里提供的demo代码,可以正常使用。

异常情况描述:
上传按钮使用的不是原生的html标签,而是另一个人写的Button组件,然后导致了一些问题。

我的代码:

<template>
<!-- 注意是另一个Button组件,不是原生的<button> -->
<Button id="pick-avatar">上传头像</Button>  
<avatar-cropper
            @uploaded="handleUploaded"
            @error="handleError"
            trigger="#pick-avatar"
            upload-url="/files/upload"
          />
</template>

<script>
//因为js代码没啥东西,先省略
</script>

最后的效果就是点击button没有反应

我自己推测应该是document.querySelector的机制导致没有找到组件加载后的id为pick-avatar的button元素。

所以目前暴露的API好像不够支持这种情况,希望可以提供下在父组件内手动触发trigger对应的内部函数的API。

我是vue新手,有些措辞可能不准确!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.