【问题标题】:Vue JS Pass Data From Parent To Child Of Child Of ChildVue JS 将数据从父级传递给子级的子级
【发布时间】:2021-06-29 15:58:56
【问题描述】:

在 Vue.js 中,如何正确地将数据从父组件传递到多层子组件链?

【问题讨论】:

    标签: vue.js state vue-props


    【解决方案1】:

    【讨论】:

      【解决方案2】:

      @RoboKozo 为您列出了一些非常棒的选择,这取决于您对数据的处理方式。

      如果它是静态数据(并且你喜欢模块化),你总是可以使用mixins。

      来自 Vue.js 文档:

      Mixins 是一种为 Vue 组件分配可重用功能的灵活方式。 mixin 对象可以包含任何组件选项。当组件使用 mixin 时,mixin 中的所有选项都会“混合”到组件自己的选项中。

      示例 1:混入

      文件/文件夹设置:

      /src/mixins/defaultDataMixin.js // Call this whatever you want
      

      /src/mixins/defaultDataMixin.js:

      export const default defaultData {
          data() {
              return {
                  property1: "Foo",
                  property2: "Bar"
              }
          }
      }; 
      

      现在,在您想要访问property1property2 的任何组件上,您只需导入您的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 共享数据

      道具向下,发射向上

      也许您在父组件中返回一些您希望传递给子组件的数据。道具是一个很好的方法!

      文件/文件夹设置

      /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。

      虽然它不是直接将数据从父组件“传递”到子组件,但您可以让父组件可以改变子组件正在观看的状态。

      假设您想要返回用户信息,然后跨多个组件访问该数据。

      文件/文件夹设置

      /.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
      

      ma​​in.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>
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2017-06-24
        • 2020-09-22
        • 1970-01-01
        • 2011-09-07
        • 2019-12-04
        • 2018-03-09
        • 2016-11-14
        • 2023-03-13
        相关资源
        最近更新 更多