如何在另一个Vue单组件中获取一个组件的数据?

17

我使用 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>

组件-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组件之间调用数据。


可能是在Vuejs中在不同组件之间共享数据的重复问题。 - Roy J
1
@RoyJ - 我认为我不会将那个作为可能的重复引用,因为该答案建议使用.sync修饰符,而这个修饰符已经从Vue中被移除。但是,毫无疑问,还有很多其他现有的问题可以为这种情况提供答案。 - PatrickSteele
5个回答

14

Vuejs使用"props"用于父子组件间通信,而使用events的“emits”用于子父组件间通信。

enter image description here

请记住,对于每个传递给子组件的prop,您都应将该prop添加到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>

这应该可以运作


13

7
有几种方法可以做到这一点,其他答案中提到了一些(没有特定顺序,请阅读下面的详细部分以获取更多信息):
  1. 使用全局事件总线(不建议)
  2. 在组件上使用props
  3. 使用v-model属性
  4. 使用sync修饰符
  5. 使用Pinia

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

1.) 使用全局事件总线

强烈建议不要使用这种方法进行组件之间的常规通信,因为像这里这样的地方已经讨论过。

2.) 在组件上使用 props

不建议使用 props 进行双向绑定,但是通过传递一个对象或数组,您可以更改该对象的属性,并且在子组件和父组件中都会观察到,而 Vue 不会在控制台中打印警告。

每次更新父组件时,所有子组件中的 props 都将使用最新值刷新。这意味着您不应尝试在子组件内部更改 prop。

道具很容易使用,是解决大多数常见问题的理想方式。
由于Vue如何观察更改,所有属性都需要在对象上可用,否则它们将不会是响应式的。 如果在Vue完成使它们可观察之后添加任何属性,则必须使用'set'
 //Normal usage
 Vue.set(aVariable, 'aNewProp', 42);
 //This is how to use it in Nuxt
 this.$set(this.historyEntry, 'date', new Date());

该对象将对组件和父级同时起作用:

如果您将一个对象/数组作为prop传递,它会自动进行双向同步 - 在子组件中更改数据,它也会在父组件中更改。

如果您通过props传递简单的值(如字符串、数字),则必须明确使用.sync修饰符

引用自 --> https://dev59.com/QVsV5IYBdhLWcg3w2h0s#35723888

3.) 使用v-model属性

v-model属性是一种语法糖,可以在父子之间轻松实现双向绑定。它与sync修饰符执行的操作相同,只是使用了特定的prop和事件来进行绑定。

这个:

 <input v-model="searchText">

与此相同:

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

其中prop必须是value,事件必须是input

4.) 使用sync修饰符

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

在父组件中可以按以下方式使用:

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

从子组件中可以发出事件来通知父组件进行任何更改:
 this.$emit('update:title', newTitle)

中译英:

5.) 使用 Pinia(或 Vuex)

目前 Pinia 是官方推荐的状态管理器/数据存储库。

Pinia 是一个针对 Vue 的存储库,它允许您在组件/页面之间共享状态。

通过使用 Pinia 存储库,更容易看到数据变化的流程,并且它们是明确定义的。通过使用Vue 开发者工具,轻松调试和回滚所做的更改。

这种方法需要一些模板代码,但如果在整个项目中使用,它将成为一种更清晰的定义如何进行更改以及从哪里进行更改的方式。

查看他们的入门指南部分。


如果您的项目已经使用了 Vuex,您可以继续使用它。
Vuex 3 和 4 将继续得到维护。但是,不太可能向其中添加新功能。Vuex 和 Pinia 可以安装在同一项目中。如果您要将现有的 Vuex 应用程序迁移到 Pinia,则可能是一个合适的选项。但是,如果您计划启动一个新项目,我们强烈建议使用 Pinia。

6
你需要实现一个系统,将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>


3

You can use .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>

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接