Vue JS 将数据从 Parent 传递到 Child 的 Child 的 Child
Vue JS Pass Data From Parent To Child Of Child Of Child
在 Vue.js 中,如何正确地将数据从 parent 组件传递到多级 child 组件链?
您有几个选择:
在此处了解更多信息:https://www.smashingmagazine.com/2020/01/data-components-vue-js/
@RoboKozo 列出了一些非常适合您的选项,这取决于您对数据的处理方式。
如果它是静态数据(并且你喜欢模块化),你总是可以使用mixins。
来自 Vue.js 文档:
Mixins are a flexible way to distribute reusable functionalities for Vue components. A mixin object can contain any component options. When a component uses a mixin, all options in the mixin will be “mixed” into the component’s own options.
示例 1:混合
File/Folder 设置:
/src/mixins/defaultDataMixin.js // Call this whatever you want
/src/mixins/defaultDataMixin.js:
export const default defaultData {
data() {
return {
property1: "Foo",
property2: "Bar"
}
}
};
现在,在您想要访问 property1
或 property2
的任何组件上,您只需导入您的 mixin。
/src/pages/MyComponent.vue
<template>
<div id="wrapper">
<div class="container">
<div class="row">
<div class="col">
{{ property1 }}
</div>
<div class="col">
{{ property2 }}
</div>
</div>
</div>
</div>
</template>
<script>
import { defaultData } from "@/mixins/defaultDataMixin"
export default {
mixins: [defaultData],
}
</script>
示例 2:通过 Props 和 Emit 共享数据
道具向下,发射向上
也许您 return 父组件中的某些数据希望传递给子组件使用。道具是做到这一点的好方法!
File/Folder 设置
/src/pages/ParentComponent.vue
/src/components/ChildComponent.vue
ParentComponent.vue
<template>
<div id="wrapper">
<div class="container">
<div class="row">
<div class="col">
<child-component :defaultDataProp="defaultData" @emitted-text="helloWorld">
</child-component>
</div>
</div>
</div>
</div>
</template>
<script>
import { defaultData } from "@/mixins/defaultDataMixin"
import ChildComponent from "@/components/ChildComponent.vue"
export default {
mixins: [defaultData],
components: {
ChildComponent
},
data() {
return {
emittedText: "",
}
},
methods: {
helloWorld(e){
this.emittedText = e;
}
}
}
</script>
ChildComponent.vue
<template>
<div id="wrapper">
<div class="container">
<div class="row">
<div class="col">
{{ defaultDataProp }}
</div>
</div>
<div class="row">
<div class="col">
<button @click="emitData">Emit Data</button>
</col>
</div>
</div>
</div>
</template>
<script>
export default {
props: {
defaultDataProp: {
type: String
}
},
data() {
return {
text: "Hello, world!"
};
},
methods: {
emitData() {
this.$emit('emitted-text', this.text);
}
}
}
</script>
很酷吧?
这些只是您可以在组件之间共享数据和功能的几种方式。
** 编辑 **
示例 3:Vuex 状态 + mapGetters
我刚注意到你也标记了这个 state
,所以我 假设 你有 already installed 并且正在使用 Vuex。
虽然它不是直接将数据从父级“传递”到子级,但您可以让父级组件改变子级组件正在监视的状态。
假设您想要 return 用户信息,然后可以跨多个组件访问该数据。
File/Folder 设置:
/.env
/src/main.js
/src/store/store.js
/src/store/modules/user.js
/src/mixins/defaultDataMixin.js
/src/util/api.js
/src/pages/ParentComponent.vue
/src/components/ChildComponent.vue
main.js
import Vue from "vue";
import Vuex from "vuex";
import { store } from "@/store/store";
// ... add whatever else you need to import and use
Vue.use(vuex); // but make sure Vue uses vuex
// Vue can "inject" the store into all child components
new Vue({
el: "#app",
store: store, // <-- provide the store to the vue instance
// ..
});
.env:
VUE_APP_API_URL='http://127.0.0.1:8000'
api.js:
import axios from "axios";
import { store } from "@/store/store";
const apiClient = axios.create({
baseURL: process.env.VUE_APP_API_URL,
});
export default apiClient;
user.js:
import apiClient from "@/util/api"
import { store } from "../store"
const userModule = {
state: () => ({
user: {
firstName: "",
}
}),
mutations: {
setUser(state, payload) {
state.user = payload;
}
},
actions: {
async loadUser({ commit, dispatch }) {
try {
const user = (await apiClient.get("/user")).data;
commit("setUser", user); // mutate the vuex state
} catch (error) {
dispatch("logout");
}
},
logout({ commit }) {
commit("setUser", {});
}
},
getters: {
firstName: (state) => {
return state.user.firstName;
}
}
};
export default userModule;
store.js
import Vue from "vue";
import Vuex from "vuex";
import userModule from "@/store/modules/user"; // Grab our newly created module
Vue.use(Vuex);
export const store = new Vuex.Store({
modules: {
userState: userModule,
},
});
defaultDataMixin.js
import { mapGetters } from "vuex";
export const default defaultData {
data() {
return {
property1: "Foo",
property2: "Bar"
}
},
// We can make use of mapGetters here
computed: {
...mapGetters(["firstName"]),
}
};
现在,Parent 和 Child 都可以访问集中状态并可以改变它。例如,让我们从父组件调用 loadUser()
并观察子组件的状态变化。
ParentComponent.vue
<template>
<div id="wrapper">
<div class="container">
<div class="row">
<div class="col" v-if="firstName != ''">
{{ firstName }}
</div>
<div class="col">
<button @click="mutateState">Click Me</button>
</div>
</div>
<div class="row">
<div class="col">
<child-component @emitted-text="helloWorld">
</child-component>
</div>
</div>
</div>
</div>
</template>
<script>
import { defaultData } from "@/mixins/defaultDataMixin"
import ChildComponent from "@/components/ChildComponent.vue"
export default {
mixins: [defaultData],
components: {
ChildComponent
},
methods: {
// our new method to mutate the user state
mutateState() {
this.$store.dispatch("loadUser");
},
helloWorld(e){
this.emittedText = e;
}
}
}
</script>
ChildComponent.vue
<template>
<div id="wrapper">
<div class="container">
<div class="row">
<div class="col">
{{ defaultData }}
</div>
</div>
<div class="row">
<div class="col">
<button @click="emitData">Emit Data</button>
</col>
</div>
</div>
</div>
</template>
<script>
import { defaultData } from "@/mixins/defaultDataMixin"
export default {
mixins: [defaultData],
data() {
return {
text: "Hello, world!"
};
},
methods: {
emitData() {
this.$emit('emitted-text', this.text);
}
},
// Let's watch for the user state to change
watch: {
firstName(newValue, oldValue) {
console.log('[state] firstName state changed to: ', newValue);
// Do whatever you want with that information
}
}
}
</script>
在 Vue.js 中,如何正确地将数据从 parent 组件传递到多级 child 组件链?
您有几个选择:
在此处了解更多信息:https://www.smashingmagazine.com/2020/01/data-components-vue-js/
@RoboKozo 列出了一些非常适合您的选项,这取决于您对数据的处理方式。
如果它是静态数据(并且你喜欢模块化),你总是可以使用mixins。
来自 Vue.js 文档:
Mixins are a flexible way to distribute reusable functionalities for Vue components. A mixin object can contain any component options. When a component uses a mixin, all options in the mixin will be “mixed” into the component’s own options.
示例 1:混合
File/Folder 设置:
/src/mixins/defaultDataMixin.js // Call this whatever you want
/src/mixins/defaultDataMixin.js:
export const default defaultData {
data() {
return {
property1: "Foo",
property2: "Bar"
}
}
};
现在,在您想要访问 property1
或 property2
的任何组件上,您只需导入您的 mixin。
/src/pages/MyComponent.vue
<template>
<div id="wrapper">
<div class="container">
<div class="row">
<div class="col">
{{ property1 }}
</div>
<div class="col">
{{ property2 }}
</div>
</div>
</div>
</div>
</template>
<script>
import { defaultData } from "@/mixins/defaultDataMixin"
export default {
mixins: [defaultData],
}
</script>
示例 2:通过 Props 和 Emit 共享数据
道具向下,发射向上
也许您 return 父组件中的某些数据希望传递给子组件使用。道具是做到这一点的好方法!
File/Folder 设置
/src/pages/ParentComponent.vue
/src/components/ChildComponent.vue
ParentComponent.vue
<template>
<div id="wrapper">
<div class="container">
<div class="row">
<div class="col">
<child-component :defaultDataProp="defaultData" @emitted-text="helloWorld">
</child-component>
</div>
</div>
</div>
</div>
</template>
<script>
import { defaultData } from "@/mixins/defaultDataMixin"
import ChildComponent from "@/components/ChildComponent.vue"
export default {
mixins: [defaultData],
components: {
ChildComponent
},
data() {
return {
emittedText: "",
}
},
methods: {
helloWorld(e){
this.emittedText = e;
}
}
}
</script>
ChildComponent.vue
<template>
<div id="wrapper">
<div class="container">
<div class="row">
<div class="col">
{{ defaultDataProp }}
</div>
</div>
<div class="row">
<div class="col">
<button @click="emitData">Emit Data</button>
</col>
</div>
</div>
</div>
</template>
<script>
export default {
props: {
defaultDataProp: {
type: String
}
},
data() {
return {
text: "Hello, world!"
};
},
methods: {
emitData() {
this.$emit('emitted-text', this.text);
}
}
}
</script>
很酷吧?
这些只是您可以在组件之间共享数据和功能的几种方式。
** 编辑 ** 示例 3:Vuex 状态 + mapGetters
我刚注意到你也标记了这个 state
,所以我 假设 你有 already installed 并且正在使用 Vuex。
虽然它不是直接将数据从父级“传递”到子级,但您可以让父级组件改变子级组件正在监视的状态。
假设您想要 return 用户信息,然后可以跨多个组件访问该数据。
File/Folder 设置:
/.env
/src/main.js
/src/store/store.js
/src/store/modules/user.js
/src/mixins/defaultDataMixin.js
/src/util/api.js
/src/pages/ParentComponent.vue
/src/components/ChildComponent.vue
main.js
import Vue from "vue";
import Vuex from "vuex";
import { store } from "@/store/store";
// ... add whatever else you need to import and use
Vue.use(vuex); // but make sure Vue uses vuex
// Vue can "inject" the store into all child components
new Vue({
el: "#app",
store: store, // <-- provide the store to the vue instance
// ..
});
.env:
VUE_APP_API_URL='http://127.0.0.1:8000'
api.js:
import axios from "axios";
import { store } from "@/store/store";
const apiClient = axios.create({
baseURL: process.env.VUE_APP_API_URL,
});
export default apiClient;
user.js:
import apiClient from "@/util/api"
import { store } from "../store"
const userModule = {
state: () => ({
user: {
firstName: "",
}
}),
mutations: {
setUser(state, payload) {
state.user = payload;
}
},
actions: {
async loadUser({ commit, dispatch }) {
try {
const user = (await apiClient.get("/user")).data;
commit("setUser", user); // mutate the vuex state
} catch (error) {
dispatch("logout");
}
},
logout({ commit }) {
commit("setUser", {});
}
},
getters: {
firstName: (state) => {
return state.user.firstName;
}
}
};
export default userModule;
store.js
import Vue from "vue";
import Vuex from "vuex";
import userModule from "@/store/modules/user"; // Grab our newly created module
Vue.use(Vuex);
export const store = new Vuex.Store({
modules: {
userState: userModule,
},
});
defaultDataMixin.js
import { mapGetters } from "vuex";
export const default defaultData {
data() {
return {
property1: "Foo",
property2: "Bar"
}
},
// We can make use of mapGetters here
computed: {
...mapGetters(["firstName"]),
}
};
现在,Parent 和 Child 都可以访问集中状态并可以改变它。例如,让我们从父组件调用 loadUser()
并观察子组件的状态变化。
ParentComponent.vue
<template>
<div id="wrapper">
<div class="container">
<div class="row">
<div class="col" v-if="firstName != ''">
{{ firstName }}
</div>
<div class="col">
<button @click="mutateState">Click Me</button>
</div>
</div>
<div class="row">
<div class="col">
<child-component @emitted-text="helloWorld">
</child-component>
</div>
</div>
</div>
</div>
</template>
<script>
import { defaultData } from "@/mixins/defaultDataMixin"
import ChildComponent from "@/components/ChildComponent.vue"
export default {
mixins: [defaultData],
components: {
ChildComponent
},
methods: {
// our new method to mutate the user state
mutateState() {
this.$store.dispatch("loadUser");
},
helloWorld(e){
this.emittedText = e;
}
}
}
</script>
ChildComponent.vue
<template>
<div id="wrapper">
<div class="container">
<div class="row">
<div class="col">
{{ defaultData }}
</div>
</div>
<div class="row">
<div class="col">
<button @click="emitData">Emit Data</button>
</col>
</div>
</div>
</div>
</template>
<script>
import { defaultData } from "@/mixins/defaultDataMixin"
export default {
mixins: [defaultData],
data() {
return {
text: "Hello, world!"
};
},
methods: {
emitData() {
this.$emit('emitted-text', this.text);
}
},
// Let's watch for the user state to change
watch: {
firstName(newValue, oldValue) {
console.log('[state] firstName state changed to: ', newValue);
// Do whatever you want with that information
}
}
}
</script>