Как использовать компонент несколько раз, передавая ему разные данные?

Я пытаюсь создать компонент закусочной для показа простых уведомлений. Его можно использовать во многих местах всего приложения, а также на одной странице. Я создал компонент как дочерний компонент и импортировал его в родительский компонент, где я хочу его использовать. В этом родительском компоненте можно много раз использовать этот дочерний элемент. Как мне реализовать так, чтобы каждый раз, когда этот компонент вызывается, он получал соответствующие данные (например, для ошибки color = red text = "error", для успеха color = "green" message = "success).

Есть предложения о том, как это реализовать?

parent.vue----------------------------

<snackbar
      :snackbar="snackbar"
      :color="color"
      :text="message"
      v-on:requestClose="close"
    />


data() {
    return {
      snackbar: false,
      color: "orange",
      timeout: 3000,
      message: "calling from employee compoenent"
    };
  },
  methods: {
    hello() {
      console.log("button clicked!!!");
      this.snackbar = true;
    },
    close() {
      this.snackbar = false;
    },


child.vue-----------------------------------------------

<template>
  <v-snackbar v-model="snackbar" right top :timeout="timeout" :color="color"
    >{{ text }}
    <v-btn dark text @click.native="$emit('requestClose')">Close</v-btn>
  </v-snackbar>
</template>

<script>
export default {
  name: "snackbar",
  data() {
    return {
      timeout: 3000
    };
  },
  props: ["snackbar", "text", "color"],

};
</script>

<style></style>


person Sameer    schedule 22.03.2020    source источник


Ответы (3)


Рекомендуется создать настраиваемую оболочку Vue plugin

плагины / снэкбар / index.js

import snackbar from './snackbar.vue'

export default {
  install (Vue) {
    // INSTALL
    if (this.installed) return
    this.installed = true

    // RENDER
    const root = new Vue({ render: h => h(snackbar) })
    root.$mount(document.body.appendChild(document.createElement('div')))

    // APIs
    let apis = Vue.prototype['$snackbar'] = {
      show: ({ text="Foo", color="blue" }) => root.$emit('show', { text, color }), // SHOW
      hide: () => root.$emit('hide') // HIDE
    }

    Vue.prototype['$snackbar'] = apis
    Vue.snackbar = apis
  }
}

плагины / снэкбар / снекбар.vue

<template>
  <v-snackbar right top v-model="show" :timeout="timeout" :color="color">
    {{ text }}
    <v-btn dark text @click.native="this.show = false">Close</v-btn>
  </v-snackbar>
</template>

<script>
export default {
  name: "snackbar",

  data() {
    return {
      show,
      timeout: 3000,
      text: "",
      color: ""
    };
  },

  mounted () {
   // LISTENING :: SHOW
   this.$root.$on('show', ({ text, color }) => {      
    this.text = text
    this.color = color
    this.show = true
   })

   // LISTENING :: HIDE
   this.$root.$on('hide', () => this.show = false)
  }
};
</script>

// main.js

import Snackbar from './plugins/snackbar/index.js'
Vue.use(Snackbar)

Чтобы show / hide в любом компоненте

this.$snackbar.show({ text: "Foo bar", color: "red" }) // OR
Vue.snackbar.show({ text: "Foo bar", color: "red" })

В зависимости от варианта использования вы можете продолжать обновлять свой плагин, добавляя больше параметров / API.


Альтернатива: с помощью event bus

событие-автобус / bus.js

// Create an event bus
import Vue from 'vue'
export default new Vue()

app.vue

<template>
 // Render the component in app.vue
 <v-snackbar 
  right top 
  v-model="snackbar.show" 
  :timeout="snackbar.timeout" 
  :color="snackbar.color"
 >
  {{ snackbar.text }}
  <v-btn 
   dark text 
   @click.native="this.snackbar.show = false"
  >
   Close
  </v-btn>
 </v-snackbar>
</template>

<script>
import bus from './event-bus/bus.js'

export default {
 data () {
  return {
   snackbar: {
    show: false,
    text: '',
    color: '',
    timeout: 3000
   }
  }
 },

 mounted () {
  // LISTEN TO SHOW
  bus.$on('show', ({ text, color }) => {
   this.snackbar.text = 'foo'
   this.snackbar.color = 'red'
   this.snackbar.show = true
  })

  // LISTEN TO HIDE
  bus.$on('hide', () => this.snackbar.show = false)
 }
}
</script>

На show / hide снэк-бар из любого компонента

import bus from './event-bus/bus.js

export default {
 mounted () {
  bus.emit('show', { text: 'Foo bar baz', color: 'orange' }) // TO SHOW
  // bus.emit('hide') // TO HIDE
 }
}

Другой способ: с помощью Vuex

Отобразите <v-snackbar> в app.vue, как это сделано в альтернативном подходе, и используйте Vuex state / getters, чтобы передать значение props v-snackbar.

person Shivam Singh    schedule 22.03.2020

Я сделал это, используя комбинацию глобальных компонентов и Vuex. Ответ немного длинен, потому что я привожу пример в описании, пожалуйста, потерпите меня :)

Сначала я создаю магазин закусок с color и text в качестве state и setSnackbar() action, который получает цвет и текст в качестве параметров. Затем вы можете создать свой Snackbar компонент и не забыть отобразить в него свои геттеры и действия. Некоторый фрагмент кода:

// snackbar component
<template>
  <v-snackbar v-model="snackbar.show" :color="snackbar.color" :timeout="6000" bottom right>
    {{ snackbar.text }}
    <v-btn dark text @click="snackbarClosed()">Close</v-btn>
  </v-snackbar>
</template>

<script lang="ts">
import Vue from "vue";
import { mapGetters, mapActions } from "vuex";

export default Vue.extend({
  computed: {
    ...mapGetters(["snackbar"])
  },
  methods: {
    snackbarClosed() {
      this.resetSnackbar();
    },
    ...mapActions(["resetSnackbar"])
  }
});
</script>
// snackbar store
const state = {
  snackbar: {
    show: false,
    text: '',
    color: ''
  }
};
const getters = {
  snackbar: (state: any) => state.snackbar
};
const actions = {
  async setSnackbar({ commit }, params) {
    commit('updateSnackbar', Object.assign({}, { show: true }, params))
  },
  async resetSnackbar({ commit }) {
    const setting: SnackbarSetting = {
      show: false,
      text: '',
      color: ''
    };
    commit('updateSnackbar', setting)
};
const mutations = {
  updateSnackbar: (state: any, snackbar: SnackbarSetting) => {
    state.show = snackbar.show;
    state.text = snackbar.text;
    state.color = snackbar.color;
  }
};

Чтобы сделать компонент Snackbar глобально доступным, импортируйте компонент Snackbar в свой main.ts и добавьте строку Vue.component('Snackbar', Snackbar); перед new Vue. Его цель - зарегистрировать ваш Snackbar компонент глобально перед инициализацией экземпляра Vue. Пример:

// main.ts
import Snackbar from './components/Snackbar.vue';

Vue.component('Snackbar', Snackbar);

new Vue({
...

Прежде чем вы захотите отобразить свою снекбар в приложении, по моей рекомендации вы должны поместить <Snackbar /> в App.vue, чтобы закусочная могла появиться перед вашими компонентами, и вы не столкнулись с отсутствием снекбара при переключении между компонентами.

Если вы хотите отобразить свою закусочную, просто сделайте это в своем компоненте:

// any of your component
methods: {
  someEvent() {
    this.someApiCall({
      // some data passing
    }).then(() => {
      this.setSnackbar({
        text: 'Data has been updated.',
        color: 'success'
      });
    }).catch(() => {
      this.setSnackbar({
        text: 'Failed to update data.',
        color: 'error'
      });
    });
  },
  ...mapActions(['setSnackbar'])
}

Надеюсь, у вас получится, пожалуйста, не стесняйтесь, дайте мне знать, если вам что-то понадобится. Вот вам дополнительный материал: Global регистрация компонентов

person jet_choong    schedule 25.03.2020

вы можете наблюдать за реквизитом в дочернем элементе, это изменит цвет, когда произойдут какие-либо изменения в родительском элементе:


watch: {
color: function(value) {
"add color value to your dom css class"
}
}
person mai elrefaey    schedule 22.03.2020