Разрешить обещание внутри метода при нажатии кнопки - PullRequest
0 голосов
/ 19 июня 2020

У меня есть своего рода «слайд-шоу», состоящее из всплывающих окон в шаблоне vue. js, где каждый слайд является отдельным компонентом, а родительский компонент вызывает каждый слайд в «for» l oop. Пользователи переходят от одного слайда к другому, нажимая кнопку внутри компонента. То, как я сейчас это настроил, когда родитель вызывает 'активирует' слайд через this.$refs, он переключает класс, чтобы сделать слайд видимым, затем создает слушателя внутри обещания, разрешая это обещание только тогда, когда слушатель активирован. Я уверен, что есть лучший способ сделать это, так как кажется, что мой код нарушает некоторые неписаные правила Javascript, определяя слушателя внутри обещания. Однако я не могу придумать лучшего способа, поскольку я относительно новичок в JS и Vue. Любая помощь или совет приветствуются.

Компонент называется «Инструкция», поскольку я использую его для объяснения различных частей моего приложения.

Кнопка для перемещения слайда: <button v-on:submit.prevent name="button-text" :id="'next-instruction-button-'+index">Next</button>

Код в компоненте Instruction, который используется для активации и деактивации содержимого:

handleClick() {
    return new Promise(res => {
        var popup = document.getElementById(`myPopup-${this.index}`);
        popup.classList.toggle("show");

        /* Not totally sure what I've built here, but it works */
        new Promise(resolve => {
            document.querySelector(`#next-instruction-button-${this.index}`).addEventListener('click', () => {
                return resolve();
            })
        })
        .then(() => {
            popup.classList.toggle("show");
            res();
        })
    })
},

Вызов из родительской функции:

async showInstructions() {
    for (let i = 1; i <= this.numInstructions; i++) {
        console.log(i)
        await this.$refs[`instruction-${i}`].handleClick();
    }
},

Код для каждого слайдов изначально здесь

1 Ответ

0 голосов
/ 19 июня 2020

Я бы предложил использовать refs и сохранить функцию Promise resolve, пока пользователь не нажмет кнопку

methods: {
  onClick() {
    this.resolve();
  },
  handleClick() {
    const popupRef = this.$refs.popupRef;
    const classList = popupRef.classList;
    return new Promise(resolve => {
        classList.toggle("show");
        this.resolve = resolve;
    })
    .then(() => {
       classList .toggle("show");
    })
  })
},

Пример

Vue.config.devtools = false;
Vue.config.productionTip = false;

Vue.component("child-component", {
  props: {
    text: String,
    response: String,
    clicked: Boolean
  },
  template: `<div class="instruction">
    <div>{{text}}</div>
    <span ref="popupRef" class="popup">Click it!</span>
    <button v-if="!clicked" @click="onClick">Ok Done!</button>
    <div v-if="clicked">{{response}}</div>
  </div>`,
  methods: {
    onClick() {
      this.resolve();
    },
    handleClick() {
      const popupRef = this.$refs.popupRef;
      const classList = popupRef.classList;
      
      return new Promise(resolve => {
          classList.toggle("show");
          this.resolve = resolve;
        })
        .then(() => {
          classList.toggle("show");
        })
    },
  }
})

new Vue({
  el: '#container',
  data() {
    return {
      text: 'Show Instructions',
      disabled: false,
      instructions: [{
          id: 1,
          text: 'Eat something!',
          response: 'Nice!',
          clicked: false
        },
        {
          id: 2,
          text: 'Work',
          response: 'Wow!',
          clicked: false
        }
      ]
    }
  },
  methods: {
    async showInstructions() {
      this.disabled = true;
      this.text = "Showing instructions...";
      
      const combined = this.instructions.map((obj, index) => [
        obj,
        this.$refs.instructions[index]
      ]);
      
      for (let [instruction, ref] of combined) {
        await ref.handleClick();
        this.$set(instruction, 'clicked', true);
      }
      
      this.text = 'Processing...';
      
      setTimeout(() => {
        this.disabled = false;
        this.text = 'Show Instructions';
      
        this.instructions = this.instructions.map(instruction => ({
          ...instruction,
          clicked: false
        }))
      }, 500);
    }
  }
});
.instruction {
  border: 1px solid black;
  padding: 10px;
}

.popup {
  position: absolute;
  opacity: 0;
  padding: 10px;
  background: black;
  color: white;
  margin-top: -10px;
  margin-left: 90px;
  
}

.popup.show {
  opacity: 1;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="container">
  <child-component ref="instructions" :key="item.id" v-bind="item" v-for="item in instructions"></child-component>
  <button :disabled="disabled" @click="showInstructions">{{text}}</button>
</div>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...