Не удается получить окончательную обрезанную версию с помощью cropperjs в моем основном компоненте vue

#javascript #vue.js #cropperjs

#javascript #vue.js #cropperjs

Вопрос:

В моем приложении laravel-vue я создал компонент ImageCropper с помощью cropperjs. А затем в моем родительском компоненте vue я динамически создаю компонент ImageCropper при изменении события загрузки файла пользователем. Я отправляю URL-адрес изображения дочернему компоненту в качестве реквизита из главного компонента. ImageCropper создается идеально, и механизм обрезки тоже работает отлично. Единственная проблема в том, что я могу отслеживать только обрезанное изображение и изменения в нем в компоненте ImageCropper, но не могу отслеживать или обновлять данные в моем главном компоненте, из которого мне нужно отправить данные в базу данных. Мой код приведен ниже:

Это компонент ImageCropper:

 <template>
    <div class="card">
        <img ref="image" :src="imageSource" style="width: 100%;">
        <img ref="destinationImage" :src="destination" class="img-fluid">

    </div>
</template>
<script>
    import Cropper from 'cropperjs';
    export default {
        name: 'ImageCropper',
        props: {
            imageSource: String,
        },
        data() {
            return {
                cropper: {},
                destination: {},
                image: {},
            }
        },
        mounted() {
            this.image = this.$refs.image;

            this.cropper = new Cropper(this.image, {
                zoomable: false,
                scalable: false,
                aspectRatio: 16 / 9,
                viewMode: 1,
                background: false,
                crop: () => {
                    const canvas = this.cropper.getCroppedCanvas();
                    this.destination = canvas.toDataURL("image/png");

                },

            });

        },




    }

</script>
  

Из этого компонента я могу отслеживать окончательное изображение и его обновления с помощью ‘this.destination’.
Это мой основной компонент:

 <template>
    <div>
        <div>
            <input @change="changePhoto($event)" name="photo" type="file">
        </div>
        <div ref="imageCropperArea"></div>
    </div>
</template>
<script>
    import ImageCropper from './../../ImageCropper.vue';
    export default {
        name: "New",
        data() {
            return {
                temp_photo: '',
                final_photo: '',

            }
        },
        components: {
            ImageCropper
        },
        methods: {
            createImageCropping(event) {
                var ComponentClass = Vue.extend(ImageCropper)
                var instance = new ComponentClass({
                    propsData: {
                        imageSource: this.form.temp_photo
                    }
                })
                instance.$mount()
                this.$refs.imageCropperArea.appendChild(instance.$el)

            },
            changePhoto(event) {
                let file = event.target.files[0];


                let reader = new FileReader();
                reader.onload = event => {
                    this.form.temp_photo = event.target.result
                    this.createImageCropping(event)

                };
                reader.readAsDataURL(file);


            },
        }

    }

</script>
  

Все, что мне нужно, это обновить мою переменную ‘final_photo’ по мере продолжения обрезки. Я искал vuex для передачи данных с помощью хранилища vue при их изменении, но, поскольку я новичок в использовании vuex, не смог настроить vuex в компоненте ImageCropper. Я мог бы получить доступ к store.js из главного компонента, но не из ImageComponent. Также не был уверен, что это правильный путь для достижения моей цели здесь.

Ответ №1:

Вы можете создать событие для отправки любых данных обратно в родительский компонент. Дополнительные сведения см. в разделе Пользовательские события.

В вашем случае вы можете сделать что-то вроде:

 ...
  mounted () {
    ...
    this.cropper = new Cropper(this.image, {
      ...
      crop: () => {
        const canvas = this.cropper.getCroppedCanvas()
        this.$emit('crop', canvas.toDataURL('image/png'))
      }
    })
  }
...
  

И

 ...
  createImageCropping (event) {
    ...
    instance.$on('crop', dataUrl => {
      // now you can dispatch an action to update state of store
    })
    ...
  }
...
  

Я не уверен, почему вы создаете экземпляр ImageCropper таким образом, но в основном вам это не нужно. Вы можете просто использовать компонент или динамический компонент. Подробнее о динамических и асинхронных компонентах.

Итак, вы можете сделать что-то вроде:

 <template>
  <div>
    ...
    <image-cropper
      v-if='!!imageSource'
      :image-source="imageSource"
      @crop="dispatchSomeAction"/>
  </div>
</template>
  

И в вашем changePhoto методе после завершения чтения просто установите imageSource :

 ...
  changePhoto (event) {
    const file = event.target.files[0]
    const reader = new FileReader()
    reader.onload = event => {
      this.imageSource = event.target.result
    }
    reader.readAsDataURL(file);
  }
...
  

Комментарии:

1. Большое спасибо, приятель @ User 28. На самом деле это первый раз, когда я работаю с vuex и кратко работаю над этим в vue. Ваши советы очень помогли