如何在向组件传递不同数据时多次使用组件?

How to use a component multiple times while passing different data to it?

我正在尝试创建一个用于显示简单通知的小吃栏组件。它可以在整个应用程序的许多地方使用,也可以在单个页面上使用。我创建了一个组件作为子组件,并将其导入到我要使用它的父组件中。在这个父组件中可以多次使用这个子组件。我应该如何以每次调用此组件时获取其适当数据的方式实现(例如错误颜色=红色文本="error",成功颜色="green"消息=“成功”)。

关于如何实施它有什么建议吗?

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>

推荐 将创建自定义包装器 Vue plugin

plugins/snackbar/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
  }
}

plugins/snackbar/snackbar.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)

To show / hide it in any component

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

根据用例,您可以使用更多参数/API 不断更新您的插件。


备选方案: 通过使用 event bus

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>

To show / hide snackbar from any component

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

在 app.vue 中渲染 <v-snackbar> 作为替代方法并使用 Vuex state / getters 传递v-snackbar 的 props 值。

你可以在child中观察道具这会在parent中发生任何变化时改变颜色:


watch: {
color: function(value) {
"add color value to your dom css class"
}
}

我是通过结合使用全局组件和 Vuex 来完成的。答案有点长,因为我在描述中提供了示例,请耐心等待:)

我首先创建了一个小吃店,其中 colortext 作为其 state 和一个 setSnackbar() action 接收颜色和文本作为参数。然后你可以创建你的 Snackbar 组件并且不要忘记将你的 getters,动作映射到它。一些代码片段:

// 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 并在 new Vue 之前添加行 Vue.component('Snackbar', Snackbar);。它的目的是在初始化 Vue 实例之前全局注册你的 Snackbar 组件。示例:

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

Vue.component('Snackbar', Snackbar);

new Vue({
...

在你想在应用程序中显示你的 snackbar 之前,根据我的建议,你应该将 <Snackbar /> 放在你的 App.vue 中,这样 snackbar 就可以出现在你的组件之前,你就不会面对在组件之间切换时缺少 snackbar。

当你想显示你的 snackbar 时,只需在你的组件中这样做:

// 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'])
}

希望你能解决,如果你需要什么,请随时告诉我。这里有一些额外的 material 给你:Global component registration