在 Vuejs 中跨不同组件共享数据

Posted

技术标签:

【中文标题】在 Vuejs 中跨不同组件共享数据【英文标题】:Share data across different components in Vuejs 【发布时间】:2016-07-01 05:39:01 【问题描述】:

鉴于下方的迷你 Vuejs 应用程序。

当我单击其中一个递增/递减按钮时,“计数器”组件中的值会更新,但“字母表”中的值不会。 关于如何在这两个组件之间共享相同数据以便它们自动更新的任何想法?

var counter = Vue.extend(
    props: ['start'],
    template: '#counter',
    data: function() 
      return 
        value: this.start
      
    ,
    methods: 
      increment: function() 
        this.value++
      ,
      decrement: function() 
        this.value--
      
    
  );

  var alphabet = Vue.extend(
    props: ['value'],
    template: '#alphabet',
    data: function() 
      return 
        value: 0
      
    
  );

  new Vue(
    el: '#app',
    data: 
      val: 5
    ,
    components: 
      counter: counter,
      alphabet: alphabet
    
  );
<script id="counter" type="text/template">
  <button @click="increment">+</button>  value 
  <button @click="decrement">-</button>
</script>
<script id="alphabet" type="text/template">  value  </script>
<div id="app">
  <counter :start="val"></counter>
  <alphabet :value="val"></alphabet>
</div>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/vue/1.0.17/vue.js"></script>

【问题讨论】:

How can I share data between non parent-child components in Vue的可能重复 【参考方案1】:

你有两个选择。

1 手动同步您的值

在您的incrementdecrement 函数中添加这句话

this.$parent.val = this.value;

并使您的字母值等于父值

computed: 
    value: function() 
        return this.$parent.val;
    
  

导致this fiddle

2 使用vuex 保持数据的全局状态

使用vuex,您可以为所有组件使用store 一个通用state。此状态将是反应性的,因此会在您更改其值时为每个组件更新。这对您的用例来说可能有点过头了,但绝对是一个需要牢记的选择

【讨论】:

那么基于上面的说法,Vuejs 主要用于创建隔离组件是否正确?第一个选择并不理想,而第二个依赖于另一个框架。 Vuejs 用于制作响应式 SPA。如果您需要扩展功能,您可以使用一组插件,例如 vue-resource 用于处理服务器交互,vue router 用于路由,vuex 用于状态管理。这和其他框架的工作方式类似,其实vuex的灵感来源于flux和redux,对于react @skay Vue 非常适合这种类型的东西,您不需要任何其他扩展,此功能是内置的。请参阅我的答案。 @jeff Yeap,我同意 - 这么简单的事情不需要任何扩展。【参考方案2】:

您的设置方式存在 2 个问题。它在这里工作:https://jsfiddle.net/j9hua7c8/

第一个问题是在counter 组件中,您创建了一个名为value 的新变量,它的值为this.start。这获取了start 的值并将其分配给value,但由于value 是一个新变量,它不再同步到start。更新版本:

var counter = Vue.extend(
  props: ['value'],
  template: '#counter',
  methods: 
    increment: function() this.value++,
    decrement: function() this.value--
  
);

第二件事是,为了让子变量双向同步,您需要在绑定上使用.sync 修饰符。默认情况下,它们只是单向绑定。更新:

<counter :value.sync="val"></counter>

如果更适合您的用例,您还可以使用 $dispatch 和 $broadcast 在父组件和子组件之间进行通信。

【讨论】:

【参考方案3】:

如前所述,您可以使用 vuex。但是,您没有必须使用 vuex。 Vuex 只是帮助强制执行如何使用全局状态的约定,并试图让做错事变得困难。

不过,只要稍加自律,您就可以轻松做到。只需创建全局对象并将其传递给数据函数中的所有组件。

【讨论】:

不需要使用全局对象,只要是父组件的属性同步到子组件即可【参考方案4】:

我花了很长时间才得出结论,我需要 VueX组件 相互通信。所以我向大家推荐,现在就开始学习VueX,这样你就不会浪费时间了。您的同事会欣赏代码标准,并将 VueX 视为首选方法。我承认,我今天通读了 VueX 网站文档的每一页,但我仍然缺乏一个工作示例。但是,我之前确实找到了 VueX Module Decorators 页面,当我使用 Vue 过渡到 Typescript 时,我将自己实现这个我喜欢的 Vue Class Component 和 Vue Property Decorator 包。 p>

我最初使用 Vue 组件 代码,例如 JavaScript 中的 this.$childrenthis.$parent.$children 来循环通过 components 到达 组件数据并在其他组件上调用方法来设置页面状态我需要的方式。我会说这是一种 dirty 方法,但如果你需要一些快速的东西,它就可以工作。我说它是 dirty,因为所有 Vue 组件 都有一个 isolated 范围。我创建的用于从组件外部访问数据的方法只打算从内部访问组件本身或从VueJS的角度来看组件的模板。然而,JavaScript 让我能够摆脱我正在做的事情,因为我知道 DOM 的结构。如果你对所看到的一切都不走运,并且你在一个项目中已经有好几天了,并且迫切需要一些东西;这是我所指的一个工作示例:(Dirty Approach)[https://jsfiddle.net/OhRyanOh/s5b21hym/].

如果您使用Dirty Approach,例如冲浪this.$childrenthis.$parent.$children;请稍后重构您的应用程序并切换到VueX。我使用这个unit-test-driver 组件来填写表单元素“for me”,这样我就可以更快地构建应用程序,并在此过程中进行测试。我正在从 Word/Excel 复制和粘贴数据,需要动态添加新的表单组件,然后用数据填充这些组件,并在剪贴板中生成 pretty XML。当我第一次学习 Vue 组件时,我在编写Dirty Approach 代码时遇到了很多错误。达到能够测试的地步变得非常麻烦,而且我从另一个文档中复制和粘贴了太多东西,这就是为什么我创建了unit-test-driver 组件来加快我的开发速度。从那以后,我将所有这些都转移到了一个基于 Vue CLI 的项目到 TypeScript,并且由于 this.$refsthis.$propsVue 的而导致 unit-test-driver 实现失败/em> 独立的组件范围。我希望我刚刚知道从 VueX 开始,并且在编写所有这些内容时,希望我可以节省其他人宝贵的时间。

在将我的应用程序转换为 TypeScript 后,我意识到 this.$parentthis.$children 成员不能很好地与 type saftey 配合使用,所以我的应用程序坏了,我不能从 DOM Elements 轻松转换为 TypeScript 组件。我不喜欢在TypeScript 中的任何地方使用&lt;any&gt; 类型,因为这会引入union types 之类的&lt;string | null | undefined&gt;,并且依赖代码将负责对type safety 进行额外的未定义/空检查,并且您开始失去价值保证。以下是相关链接:Basic Types(检查--strictNullChecks、Douglous Crockford Vid、Null and Undefined。

我需要为组件通信找到另一种方式。我尝试改用this.$refs,因为它是访问 DOM Elements 的最佳实践,然后无法访问子组件上的调用函数...即使在 @987654356 之后@在mounted(): Promise&lt;void&gt;。我也尝试了this.$props 方法,但是对于在组件之间共享数据无效,但更多的是通过在组件模板中的属性中绑定数据将数据传递给孩子 标签。我还沿着 Dodo 的道路前进,更新了我自己的 TypeScript Vue 组件 并传递了自实例化组件的环绕数组,只是在使用v-forVue 有它自己的游戏计划,并且还为数组中的每一行实例化了它自己的组件。我创建并链接的自引用组件,没有包含与DOM组件相同的数据,因为Vue没有使用我自己实例化的组件数组,不管我自己将它们的数组和值分配给this.$refs,以及两者之间的每种组合。如果您对需要在 DOM 中显示的自己的组件使用 new 运算符,那么这是一个糟糕的设计选择。我应该能够通过 VueX 来完成我使用 Isolated ScopesShared Global Component State 所做的一切。求助于this.$props 将初始化值传递给子组件,否则使用VueX 来表示共享组件状态

在我弄清楚 VueX 是什么之前,我的最后一种方法是使用 global bus 方法,由于开发,这对于大型应用程序来说并不优雅时间复杂性。这个概念也记录在 VueJS Component Edge Cases 页面上,在标题 Accessing the Root Instance 下,然后用后续点进行说明:"This can be convenient for demos or very small apps with a handful of components. However, the pattern does not scale well to medium or large-scale applications, so we strongly recommend using Vuex to manage state in most cases."

不管怎样,我现在要回退到自己弄清楚 VueX 以实现我自己的实现。也许我可以稍后使用更好的 VueJs/TypeScript 示例来编辑它。我暂时没有,现在可能有一个。我的犹豫是没有干净的 TypeScript VueX 示例,当我第一次查看时,我并不立即知道我的场景用法,所以我像瘟疫一样避免它......只有然后我完全不知道为什么我的组件上有未定义的函数,我试图在mount/nextTicklolMount/NextTick之后通过this.$refs获取数据。是的,我绝对需要 VueX,尤其是 TypeScript

【讨论】:

以上是关于在 Vuejs 中跨不同组件共享数据的主要内容,如果未能解决你的问题,请参考以下文章

如何在 VueJS 中的组件之间共享数据

在 Apache Spark 中跨执行程序共享数据

我可以在 React 中跨多个树共享一个组件实例吗?

在池中跨 Akka Actor 实例共享可变数据

如何在 react.js 中跨子组件持久化数据或状态?

与路由器视图组件vue js共享根数据