【问题标题】:How to use a component multiple times while passing different data to it?如何在向组件传递不同数据的同时多次使用组件?
【发布时间】:2020-07-03 01:37:06
【问题描述】:

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

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

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.js notifications components vue-component snackbar


    【解决方案1】:

    推荐是创建一个自定义包装器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
      }
    }
    

    插件/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)
    

    show / hide 它在 any 组件中

    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 来自 any 组件的小吃吧

    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 中渲染 &lt;v-snackbar&gt; 以替代方法并使用 Vuex state / getters 将值传递给 v-snackbar 的 props

    【讨论】:

      【解决方案2】:

      我通过使用全局组件和 Vuex 的组合来做到这一点。答案有点冗长,因为我在描述中提供了示例,请多多包涵:)

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

      // 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之前,根据我的建议你应该把&lt;Snackbar /&gt;放在你的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'])
      }
      

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

      【讨论】:

        【解决方案3】:

        你可以观察孩子的道具,当父母发生任何变化时,它会改变颜色:

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

        【讨论】:

          猜你喜欢
          • 2020-11-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2020-01-13
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多