从另一个组件中的一个 Vue 单个组件获取数据?

Posted

技术标签:

【中文标题】从另一个组件中的一个 Vue 单个组件获取数据?【英文标题】:Get data from one Vue single component in another component? 【发布时间】: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 组件之间调用数据..

【问题讨论】:

Share data across different components in Vuejs的可能重复 @RoyJ - 我认为我不会将其作为可能的重复项,因为该答案建议使用具有been removed from vue 的.sync 修饰符。但是,可以肯定的是,对于这种情况,提供商还可以回答许多其他现有问题。 【参考方案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】:

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

    使用global eventbus 使用props on components 使用v-model attribute 使用sync modifier 使用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://***.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

【讨论】:

以上是关于从另一个组件中的一个 Vue 单个组件获取数据?的主要内容,如果未能解决你的问题,请参考以下文章

Vue-test-utils 模拟从另一个组件获取响应

将 vue 中的数据从单个父组件传递到子组件

从另一个组件中更改一个组件中的属性值

从另一个组件vue js和laravel调用方法

Vue.js 模态窗口在从另一个组件单击时未打开

Vue 使用 vuex 从另一个组件控制和更新状态