Cara yang betul untuk mencapai penyahgandingan komponen
P粉476475551
P粉476475551 2023-09-14 10:57:11
0
1
596

Saya berurusan dengan komunikasi antara dua komponen (menggunakan Vue 2), salah satunya ialah butang, yang boleh mempunyai keadaan seperti permulaan, pemuatan dan penyiapan (berjaya atau gagal), untuk setiap keadaan butang saya mungkin memaparkan keadaan yang berbeza teks, ikon berbeza (memuat: ikon putaran, berjaya diselesaikan: tandakan, penyelesaian ralat: x), saya juga mempunyai borang yang akan menggunakan komponen butang. Saya tidak pasti cara menukar keadaan butang berdasarkan keadaan semasa penyerahan borang. Sila lihat kod di bawah.

Komponen butang saya:

<template>
 <button
    class="ui-button"
    @click="clicked"
    :data-status-type="status_type"
    :disabled="is_disabled"
    :type="type"
  >
    <i :class="icon" v-if="is_disabled || concluded"></i>
    {{ title }}
  </button>         
</template>

<script>
export default {
  props: {
    title: {
      type: String,
    },
    type: {
      default: "button",
      type: String,
    },
  },
  data() {
    return {
      concluded: false,
      icon: "fa fa-spin ",
      is_disabled: false,
      status_type: "success",
    };
  },
  methods: {
    clicked() {
      if (!this.is_disabled) {
        this.$emit(
          "clicked",
          () => {
            this.is_disabled = true;
            this.icon = "fa fa-spin fas fa-spinner";
          },
          (succeeded) => {
            this.is_disabled = false;
            this.concluded = true;
            this.icon = succeeded ? "fas fa-check" : "fas fa-xmark";
            this.status_type = succeeded ? "success" : "error";
            setTimeout(() => {
              this.concluded = false;
              this.icon = "";
              this.status_type = "";
            }, 1500);
          }
        );
      }
    },
  },
};
</script>

Komponen borang saya:

<template>
  <div>
    <ThePages :parents="accompaniments">
       <!--  ... some reactive stuff  -->
      <template #extra_button>
        <TheButton @clicked="sendItemToCart" :title="button_text" :disabled="button_disabled" />
      </template>
    </ThePages>
  </div>
</template>

<script>
import axios from 'axios'
import FormatHelper from '../helpers/FormatHelper'
import SwalHelper from '../helpers/SwalHelper'
import TheButton from './TheButton.vue'
import ThePages from './ThePages.vue'
import TheQuantityPicker from './TheQuantityPicker.vue'

export default {
  props: ['product'],
  components: {
    TheButton,
    ThePages,
    TheQuantityPicker,
  },
  data() {
    return {
      accompaniments: this.product.accompaniment_categories,
      button_text: '',
      button_disabled: false,
      format_helper: FormatHelper.toBRCurrency,
      observation: '',
      quantity: 1,
      success: false,
    }
  },
  created() {
    this.addQuantityPropToAccompaniments()
    this.availability()
  },
  methods: {
    // ... some other methods
    async sendItemToCart(startLoading, concludedSuccessfully) {
      startLoading()  // This will change the button state
      this.button_text = 'Adicionando...'
      await axios
        .post(route('cart.add'), {
          accompaniments: this.buildAccompanimentsArray(),
          id: this.product.id,
          quantity: this.quantity,
          observation: this.observation,
        })
        .then(() => {
          concludedSuccessfully(true)  // This will change the button state
          this.button_text = 'Adicionado'
          SwalHelper.productAddedSuccessfully()
        })
        .catch((error) => {
          concludedSuccessfully(false)  // This will change the button state
          if (
            error?.response?.data?.message ==
            'Este produto atingiu a quantidade máxima para este pedido.'
          ) {
            SwalHelper.genericError(error?.response?.data?.message)
          } else {
            SwalHelper.genericError()
          }
          this.button_text = 'Adicionar ao carrinho'
        })
    },
  },
}
</script>

Dalam kod di atas, anda boleh melihat cara saya menukar keadaan butang berdasarkan keadaan borang: Butang saya mengeluarkan dua fungsi apabila diklik (startLoading, includedSuccessfully), dan saya kemudian menggunakan kedua-dua fungsi ini dalam sendItemToCart.

Ini nampaknya menggandingkan kedua-dua komponen itu terlalu banyak, kerana saya perlu menghantar fungsi ini sebagai parameter kepada kaedah komponen induk. Selain itu, saya mempunyai idea lain tentang cara melakukan ini, iaitu memberi setiap butang rujukan dan kemudian memanggil kaedahnya menggunakan ref dalam komponen induk. Idea ini berbunyi sedikit seperti "komposisi dan bukannya warisan" dalam pengaturcaraan berorientasikan objek, di mana saya hanya meminta objek/komponen untuk melakukan sesuatu, tetapi dalam kes ini, tanpa mengambil fungsi sebagai parameter.

Nah, kedua-dua kes di atas kelihatan lebih baik daripada mencipta pembolehubah untuk setiap butang yang mungkin saya miliki, tetapi ia kelihatan seperti ia boleh diperbaiki. Jadi apa yang saya cari ialah: Bagaimanakah saya boleh memisahkan komponen saya dengan lebih baik?

P粉476475551
P粉476475551

membalas semua(1)
P粉023650014

Jika kita bercakap tentang Vue 3 (anda tidak menyatakan versi Vue, jadi tidak pasti ia Vue 2), anda mungkin sedang mencari provide/inject:

https://vuejs.org/guide/components/provide-inject.html

Jadi, jika anda mempunyai komponen induk dan sekumpulan komponen anak yang hanya boleh muncul sebagai keturunan komponen induk (seperti borang dan kotak input), anda boleh providenyatakan borang:

OP mengulas bahawa butang mungkin muncul di tempat lain juga, jadi kita harus menggunakan kedua-dua prop dan menyediakan. Jika tiada borang, kita boleh menggunakan prop sebagai nilai suntikan lalai.

Dalam komponen bentuk:

<script setup>

import {reactive, provide} from 'vue';

const form = reactive({button_disabled: false, button_text: '', sendItemToCart});
provide('form', form);

function sendItemToCart(){
  // your logic here
}

</script>

<template>
  <div>
    <ThePages :parents="accompaniments">
       <!--  ... some reactive stuff  -->
      <template #extra_button>
        <TheButton />
      </template>
    </ThePages>
  </div>
</template>

Dalam komponen butang:

<script setup>

import {inject} from 'vue';

const props = defineProps('button_disabled button_text'.split(' '));
const form = inject('form', props); // use either provide of props

</setup>

<template>
 <button
    class="ui-button"
    @click="() => form.sendItemToCart ? form.sendItemToCart() : $emit('clicked')"
    :data-status-type="status_type"
    :disabled="form.button_disabled"
    :type="type"
  >
    <i :class="icon" v-if="form.button_disabled || concluded"></i>
    {{ form.button_text }}
  </button>         
</template>

Laraskan kod pada API Pilihan.

Dikemas kini dengan Vue 2

OP membetulkan jawapan, menggunakan Vue 2. Jadi...

Nasib baik, Vue 2 juga menyokongnyaprovide/inject! Satu-satunya masalah ialah bagaimana untuk membuat menyediakan responsif, yang saya rasa diselesaikan di sini:

Bagaimana cara saya menjadikan Vue 2 Provide / Inject API reaktif?

Muat turun terkini
Lagi>
kesan web
Kod sumber laman web
Bahan laman web
Templat hujung hadapan