【问题标题】:Get data from one Vue single component in another component?从另一个组件中的一个 Vue 单个组件获取数据?
【发布时间】:2018-07-08 02:45:01
【问题描述】:

我使用Vue.js 2.5.13 并具有这样的结构:

component-one.vue

    <template>
      <div>
        <input type="text" v-model="input_one">
        <component-two></component-two>
      </div>
    </template>

    <script>
      import ComponentTwo from 'component-two.vue'

      export default {
        name: "component-one",
        components: {
          ComponentTwo
        },
        data() {
          return {
            input_one: 'Hello from ComponentOne',
            input_two: ... // <-- I want to get value from ComponentTwo input_two (v-model) here
          }
        }
      }
    </script>

component-two.vue

    <template>
      <div>
        <input type="text" v-model="input_two">
      </div>
    </template>

    <script>
      export default {
        name: "component-two",
        data() {
          return {
            input_one: 'Hello from ComponentTwo'
          }
        }
      }
    </script>

如何从组件ComponentOne中的ComponentTwo获取数据?这对我来说很重要,因为我有许多类似的带有字段的组件(巨大的注册站点表单)并且不知道在 Vue 组件之间调用数据..

【问题讨论】:

标签: vue.js vuejs2 vue-component


【解决方案1】:

您可以使用全局事件总线轻松实现此目的。

https://alligator.io/vuejs/global-event-bus/

对于更大、更复杂的应用程序,我建议使用状态管理工具,例如 vuex。

https://vuex.vuejs.org/en/

【讨论】:

    【解决方案2】:

    您可以使用.sync Modifier

    <template>
      <div>
        <input type="text" v-model="input_one">
        <component-two :secondValue.sync="input_two"></component-two>
      </div>
    </template>
    
    <script>
      import ComponentTwo from 'component-two.vue'
    
      export default {
        name: "component-one",
        components: {
          ComponentTwo
        },
        data() {
          return {
            input_one: 'Hello from ComponentOne',
            input_two: ''
          }
        }
      }
    </script>
    

    component-two.vue:

    <template>
      <div>
        <input type="text" v-model="input_two">
      </div>
    </template>
    
    <script>
      export default {
        name: "component-two",
        data() {
          return {
            input_one: 'Hello from ComponentTwo',
            input_two: ''
          },
          watch: {
            input_two : function(val){
              this.$emit('update:secondValue', val)
            }
          }
        }
      }
    </script>
    

    【讨论】:

      【解决方案3】:

      您需要实现一个将 v-model 发送回父级的系统。

      这可以通过使用 component-two 内部的计算属性来完成,该属性在其 set 方法中发出更改。

      例子:

      Vue.component('component-two', {
        name: 'component-two',
        template: '#component-two-template',
        props: {
          value: {
            required: true,
            type: String,
          },
        },
        computed: {
          message: {
            get() {
              return this.value;
            },
            set(val) {
              this.$emit('input', val);
            },
          },
        },
      });
      
      var app = new Vue({
        el: '#app',
        data: {
          message1: 'm1',
          message2: 'm2',
        },
      });
      <script src="https://unpkg.com/vue@2.0.1/dist/vue.js"></script>
      <script type="text/x-template" id="component-two-template">
        <input type="text" v-model="message"/>
      </script>
      <div id="app">
        <input type="text" v-model="message1"/>
        <component-two v-model="message2"></component-two>
        <p>Output</p>
        <pre>{{message1}}</pre>
        <pre>{{message2}}</pre>
      </div>

      【讨论】:

        【解决方案4】:

        Vuejs 使用 "props" 进行父/子通信,使用 "emit" events 进行子/父通信

        您必须记住,对于您传递给子组件的每个道具,您都应该将这些道具传递给 props 数组。这同样适用于事件,您发出的每个事件都应该在父组件中捕获,所以:

        component-one.vue:

            <template>
              <div>
                <input type="text" v-model="input_one">
                <component-two
                    @CustomEventInputChanged="doSomenthing">
                </component-two>
              </div>
            </template>
        
            <script>
              import ComponentTwo from 'component-two.vue'
        
              export default {
                name: "component-one",
                components: {
                  ComponentTwo
                },
                data() {
                  return {
                    input_one: 'Hello from ComponentOne',
                    input_two: ''
                  }
                },
                methods: {
                    doSomenthing ( data ) {
                        this.input_two = data;
                    }
                }
              }
            </script>
        

        component-two.vue:

            <template>
              <div>
                <input type="text" v-model="input_two" @change="emitEventChanged>
              </div>
            </template>
        
            <script>
              export default {
                name: "component-two",
                data() {
                  return {
                    input_one: 'Hello from ComponentTwo'
                  }
                },
                methods: {
                    emitEventChanged () {
                        this.$emit('CustomEventInputChanged', this.input_two);
                    }
                }
        
              }
            </script>
        

        这应该可以工作

        【讨论】:

          【解决方案5】:

          有几种方法可以做到,其他答案中也提到了一些:
          排名不分先后,请阅读下面的详细部分了解更多信息)

          1. 使用global eventbus
          2. 使用props on components
          3. 使用v-model attribute
          4. 使用sync modifier
          5. 使用Vuex

          对于双向绑定,请记住,它可能会导致难以维护的突变链, 引用自文档:

          不幸的是,真正的双向绑定会产生维护问题,因为子组件可以使父组件发生变异,而该变异的来源在父组件和子组件中都不明显。

          以下是可用方法的一些详细信息:

          1.) 使用全局事件总线

          强烈建议不要将这种方法用于组件之间的任何类型的公共通信,正如here

          等许多地方所讨论的那样

          2.) 在组件上使用道具

          道具易于使用,是解决最常见问题的理想方法。
          因为how Vue observes changes,所有属性都需要在对象上可用,否则它们将不会是反应性的。 如果在 Vue 完成使它们可观察之后添加任何属性,则必须使用 'set'

           //Normal usage
           Vue.set(aVariable, 'aNewProp', 42);
           //This is how to use it in Nuxt
           this.$set(this.historyEntry, 'date', new Date());
          

          该对象对组件和父级都是响应式的:

          如果您将对象/数组作为道具传递,它会自动进行双向同步 - 更改 子,它在父中被改变了。

          如果您传递简单的值(字符串、数字) 通过道具,您必须明确使用.sync modifier

          引自 --> https://stackoverflow.com/a/35723888/1087372

          3.) 使用 v-model 属性

          v-model 属性是一种语法糖,可以在父子节点之间轻松进行双向绑定。它与同步修饰符的作用相同,只是它使用特定的道具和特定的事件进行绑定

          这个:

           <input v-model="searchText">
          

          和这个是一样的:

           <input
             v-bind:value="searchText"
             v-on:input="searchText = $event.target.value"
           >
          

          prop 必须是 value 且 event 必须是 input

          4.) 使用同步修饰符

          sync 修饰符也是语法糖,与 v-model 的作用相同,只是 prop 和 event 名称由所使用的任何内容设置。

          在父级中可以如下使用:

           <text-document v-bind:title.sync="doc.title"></text-document>
          

          可以从子级发出事件以通知父级任何更改:

           this.$emit('update:title', newTitle)
          

          5.) 使用 Vuex

          Vuex 是一个可以从每个组件访问的数据存储。 可以订阅更改。

          通过使用 Vuex 存储,可以更轻松地查看数据突变的流动,并且它们是明确定义的。通过使用vue developer tools,可以轻松调试和回滚所做的更改。

          这种方法需要更多样板,但如果在整个项目中使用,它会成为一种更清晰的方式来定义如何进行更改以及从何处进行更改。

          getting started guide

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2014-02-20
            • 2021-02-16
            • 2022-11-04
            • 2018-01-12
            • 2019-02-20
            相关资源
            最近更新 更多