Solucionado (ver solução)
Solucionado
(ver solução)
2
respostas

Vue3 desafio do botão - Forma que desenvolvi está correta?

Galera, no desafio de criar um componente para o botão, dei uma improvisada e fiz dessa forma:

Parte que chamo o botão no componente temporizador:

<template>
  <div class="is-flex is-align-items-center is-justify-content-space-between">
    <CronometroPrincipal :tempoEmSegundos="tempoEmSegundos" />
    <BotaoPrincipal :icon="iconPlay" :nomeBotao="nomeBotaoPlay" :iniciar="iniciar" :cronometroRodando="cronometroRodando"/>
    <BotaoPrincipal :icon="iconStop" :nomeBotao="nomeBotaoStop" :finalizar="finalizar" :cronometroRodando="!cronometroRodando"/>
  </div>
</template>

<script lang="ts">
import { defineComponent } from "vue";
import CronometroPrincipal from "./CronometroPrincipal.vue";
import BotaoPrincipal from "./BotaoPrincipal.vue";

export default defineComponent({
  name: "TemporizadorPrincipal",
  emits: ['aoTemporizadorFinalizado'], 

  components: {
    CronometroPrincipal,
    BotaoPrincipal
  },

  data() {
    return {
      tempoEmSegundos: 0,
      cronometro: 0, 
      cronometroRodando: false,
      iconPlay: 'fas fa-play',
      iconStop: 'fas fa-stop',
      nomeBotaoPlay: 'play',
      nomeBotaoStop: 'stop',
    };
  },

  methods: {
    iniciar() {
      this.cronometroRodando = true;

      this.cronometro = setInterval(() => {
        this.tempoEmSegundos += 1; 
      }, 1000);
    },

    finalizar() {
      this.cronometroRodando = false;
      clearInterval(this.cronometro); 
      this.$emit('aoTemporizadorFinalizado', this.tempoEmSegundos);
      this.tempoEmSegundos = 0;
    },
  },
});
</script>

Parte do componente do botao, ao invés de criar uma função para validar o estado, criei uma condicional ternária:

<template>
  <button class="button" @click="estado" :disabled="cronometroRodando">
    <span class="icon">
      <i :class="icon"></i>
    </span>
    <span>{{ nomeBotao }}</span>
  </button>
</template>

<script lang="ts">

import {defineComponent} from 'vue'

export default defineComponent({
    name: 'BotaoPrincipal',
    props: {        
        iniciar: {},
        finalizar: {},            
        icon: {
            type: String, 
            required: true            
        },            
        nomeBotao: {
            type: String, 
            required: true 
        },
        cronometroRodando: {
            type: Boolean
        },
    },

    data () {
        return {
            estado: this.iniciar ? this.iniciar : this.finalizar,
        }   
    },    
})

</script>

Obs: Está funcionando sem erros porem não sei se podemos fazer dessa forma..

2 respostas
solução!

Grande Roberto!

Primeiramente, que bom que tu topou encarar o desafio. Sobre a sua abordagem, o ponto que eu observei foi...

Imagine que tu vai usar esse componente em outro lugar da aplicação, como por exemplo para submeter uma outra funcionalidade qualquer, por exemplo abrir uma modal.

Nesse caso, como ficaria?

Desse jeito, o componente está muito acoplado com a funcionalidade de iniciar/finalizar o cronômetro.

E a ideia de componentes desse tipo é de serem o mais genéricos e desacoplados possível.

Consegue pensar numa outra maneira de implementá-lo? :)

De repente, usando os eventos do Vue? Assim ele vai ficar completamente desacoplado do cronômetro.

Hummm, faz sentido! fiz a alteração conforme a sua sujestão da aula utilizando o "emits" :

<template>
  <div class="is-flex is-align-items-center is-justify-content-space-between">
    <CronometroPrincipal :tempoEmSegundos="tempoEmSegundos" />
    <!-- foi passado o valor da propriedade a ser utilizado no component -->
    <BotaoPrincipal :icon="iconPlay" :nomeBotao="nomeBotaoPlay" @clicado="iniciar" :desabilitado="cronometroRodando"/>
    <BotaoPrincipal :icon="iconStop" :nomeBotao="nomeBotaoStop" @clicado="finalizar" :desabilitado="!cronometroRodando"/>
  </div>
</template>

<script lang="ts">
import { defineComponent } from "vue";
import CronometroPrincipal from "./CronometroPrincipal.vue";
import BotaoPrincipal from "./BotaoPrincipal.vue";

export default defineComponent({
  name: "TemporizadorPrincipal",
  emits: ['aoTemporizadorFinalizado'], 

  components: {
    CronometroPrincipal,
    BotaoPrincipal
  },

  data() {
    return {
      tempoEmSegundos: 0,
      cronometro: 0, 
      cronometroRodando: false,
      iconPlay: 'fas fa-play',
      iconStop: 'fas fa-stop',
      nomeBotaoPlay: 'play',
      nomeBotaoStop: 'stop',
    };
  },

  methods: {
    iniciar() {
      this.cronometroRodando = true;

      this.cronometro = setInterval(() => {
        this.tempoEmSegundos += 1; 
      }, 1000);
    },

    finalizar() {
      this.cronometroRodando = false;
      clearInterval(this.cronometro); 
      this.$emit('aoTemporizadorFinalizado', this.tempoEmSegundos);
      this.tempoEmSegundos = 0;
    },
  },
});
</script>

Componente botão:

<template>
  <button class="button" @click="clicadoDados" :disabled="desabilitado">
    <span class="icon">
      <i :class="icon"></i>
    </span>
    <span>{{ nomeBotao }}</span>
  </button>
</template>

<script lang="ts">
import {defineComponent} from 'vue'

export default defineComponent({
    name: 'BotaoPrincipal',
    emits: ['clicado'],
    props: {       
        icon: {
            type: String,
            required: true            
        },            
        nomeBotao: {
            type: String,
            required: true 
        },
        desabilitado: {
            type: Boolean
        },
    },

    methods: {
        clicadoDados () : void {
           console.log( this.$emit('clicado'));
        }
    }

})

</script>