如何在向组件传递不同数据时多次使用组件?
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 来完成的。答案有点长,因为我在描述中提供了示例,请耐心等待:)
我首先创建了一个小吃店,其中 color
和 text
作为其 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
我正在尝试创建一个用于显示简单通知的小吃栏组件。它可以在整个应用程序的许多地方使用,也可以在单个页面上使用。我创建了一个组件作为子组件,并将其导入到我要使用它的父组件中。在这个父组件中可以多次使用这个子组件。我应该如何以每次调用此组件时获取其适当数据的方式实现(例如错误颜色=红色文本="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 来完成的。答案有点长,因为我在描述中提供了示例,请耐心等待:)
我首先创建了一个小吃店,其中 color
和 text
作为其 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