В моем приложении у меня есть несколько кнопок «загрузки», и я хочу отобразить спиннер / загрузчик для этой конкретной кнопки, когда пользователь нажимает на нее. После завершения загрузки я хочу удалить этот спиннер / загрузчик.

У меня есть кнопки, вложенные в компонент, поэтому в файле для кнопки я получаю реквизит от родителя, а затем сохраняю его локально, чтобы загрузчик не отображался для всех кнопок загрузки. Но когда значение изменяется в родителе, ребенок не получает правильное значение опоры.

< Сильный > App.vue :

<template>
  <upload-button
    :uploadComplete="uploadCompleteBoolean"
    @startUpload="upload">
  </upload-button>
</template>

<script>
  data(){
    return {
      uploadCompleteBoolean: true
    }
  },

  methods: {
    upload(){
      this.uploadCompleteBoolean = false
      // do stuff to upload, then when finished,
      this.uploadCompleteBoolean = true
    }

</script>

< Сильный > Button.vue :

<template>
  <button
    @click="onClick">
  <button>
</template>


<script>
  props: {
    uploadComplete: {
      type: Boolean
    }

  data(){
    return {
      uploadingComplete: this.uploadComplete
    }
  },

  methods: {
    onClick(){
      this.uploadingComplete = false
      this.$emit('startUpload')
    }

</script>
0
jj008 21 Авг 2018 в 01:31

3 ответа

Лучший ответ

Исправлено имя события и имя проп, тогда оно должно работать.

  1. Как говорится в руководстве Vue: пользовательское имя события, рекомендуется Vue всегда используйте kebab-case для имен событий. поэтому вы должны использовать this.$emit('start-upload'), затем в шаблоне используйте <upload-button @start-upload="upload"> </upload-button>

  2. Руководство по Vue: реквизиты говорит,

Имена атрибутов HTML не чувствительны к регистру, поэтому браузеры будут интерпретировать любые заглавные буквы как строчные. Это означает, что когда вы используете шаблоны в DOM, имена пропеллеров camelCased должны использовать их эквиваленты в кебабе (с разделителями-дефисами)

Поэтому измените :uploadComplete="uploadCompleteBoolean" на :upload-complete="uploadCompleteBoolean"

Изменить . Только что заметил, что вы упомянули свойство данных = uploadingComplete.

Это легко исправить, добавьте один час для props=uploadComplete.

Ниже приведено одно простое демо:

Vue.config.productionTip = false
Vue.component('upload-button', {
  template: `<div>  <button @click="onClick">Upload for Data: {{uploadingComplete}} Props: {{uploadComplete}}</button>
         </div>`,
  props: {
    uploadComplete: {
      type: Boolean
    }
  },
  data() {
    return {
      uploadingComplete: this.uploadComplete
    }
  },
  watch: { // watch prop=uploadComplete, if change, sync to data property=uploadingComplete
    uploadComplete: function (newVal) {
      this.uploadingComplete = newVal
    }
  },
  methods: {
    onClick() {
      this.uploadingComplete = false
      this.$emit('start-upload')
    }
  }
})

new Vue({
  el: '#app',
  data() {
    return {
      uploadCompleteBoolean: true
    }
  },

  methods: {
    upload() {
      this.uploadCompleteBoolean = false
      // do stuff to upload, then when finished,
      this.uploadCompleteBoolean = true
    },
    changeStatus() {
      this.uploadCompleteBoolean = !this.uploadCompleteBoolean
    }
  }
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.js"></script>
<div id="app">
  <button @click="changeStatus()">Toggle Status {{uploadCompleteBoolean}}</button>
  <p>Status: {{uploadCompleteBoolean}}</p>
  <upload-button :upload-complete="uploadCompleteBoolean" @start-upload="upload">
  </upload-button>
</div>
1
Sphinx 21 Авг 2018 в 00:45

Компонент UploadButton не должен иметь uploadingComplete в качестве локального состояния (данные); это только усложняет компонент, так как вы пытаетесь смешать данные uploadComplete prop и uploadingComplete.

Видимость прядильщика должна управляться родительским компонентом через опору, сама кнопка не должна отвечать за управление видимостью прядильщика через локальное состояние в ответ на нажатия кнопки.

Просто сделайте что-нибудь вроде этого:

Vue.component('upload-button', {
  template: '#upload-button',
  props: ['uploading'],
});

new Vue({
  el: '#app',
  data: {
    uploading1: false,
    uploading2: false,
  },
  methods: {
    upload1() {
      this.uploading1 = true;
      setTimeout(() => this.uploading1 = false, Math.random() * 1000);
    },
    upload2() {
      this.uploading2 = true;
      setTimeout(() => this.uploading2 = false, Math.random() * 1000);
    },
  },
});
<script src="https://rawgit.com/vuejs/vue/dev/dist/vue.js"></script>

<div id="app">
  <upload-button :uploading="uploading1" @click="upload1">Upload 1</upload-button>
  <upload-button :uploading="uploading2" @click="upload2">Upload 2</upload-button>
</div>

<template id="upload-button">
  <button @click="$emit('click')">
    <template v-if="uploading">Uploading...</template>
    <slot v-else></slot>
  </button>
</template>
1
Decade Moon 21 Авг 2018 в 01:34

Ваш вопрос кажется немного двусмысленным. Вы можете использовать watch в этом объекте props внутри дочернего компонента следующим образом:

watch:{
    uploadComplete:{
        handler(val){
            //val gives you the updated value 
        }, deep:true
     },
}

Добавив deep в true, он будет следить за вложенными свойствами в этом объекте; если одно из свойств изменилось, вы получите новую переменную prop из val для получения дополнительной информации: https://vuejs.org/v2/api/#vm-watch

Если не то, что вы хотели, я сделал очень быстрый пример, проверьте это, надеюсь, это поможет: https://jsfiddle.net/K_Younes/64d8mbs1/

1
K. Younes 21 Авг 2018 в 02:47
51939319