将计算属性嵌套在一个对象中以进行代码维护 (Vue)

Posted

技术标签:

【中文标题】将计算属性嵌套在一个对象中以进行代码维护 (Vue)【英文标题】:Nesting computed properties in one object for code maintenance (Vue) 【发布时间】:2021-07-19 16:50:45 【问题描述】:

就清洁逻辑和维护而言,以下场景的最佳做法是什么?

我的用例是有一个查询对象,它的参数是一堆text和之前查询的结果。

我最初认为代码结构如下(见伪代码):

data() 
  return 
     queries : 
       q1 :  data: `$this.text + $this.formerResults` 
       // q2, q3...
     ,
     formerResults : ''
  
,
methods : 
  makeQuery : function() 
    let vm = this;

    axios( /* param of the query, data : this.queries.q1 */ )
     .then((response) =>  vm.formerResults += /* add the results */ )

这个问题是formerResults 确实被附加了,但在下一个查询q1 中注入时结果为undefined。我不知道为什么,但通过将查询 q1 构造为计算属性解决了这个问题。

您能说出为什么在使用属性时逻辑会失败,并且可以使用计算属性吗?

computed: 
   q1() 
      return 
          // same as above
      
   
   // q2, q3 ...

并在我的方法中调用它:

axios( /* param of the query, data : this.q1 */ );

可以看到textformerResults这两个参数都通过了。

但是,我想将查询(q1、q2、q3..)分组在同一个对象 queries 下,就像在 data() 中一样:这是为了代码清晰,因为所有这些查询都是针对相同的url,我可能还有其他的。

但是尝试:

computed: 
    computedQueries : 
       q1() 
          return 
          // same as above
        
       ,
       // q2, q3 ...
    

并在我的方法中这样称呼它:

axios( /* param of the query, data : this.computedQueries.q1 */ )

会导致vue报错:

Error in v-on handler: "TypeError: Cannot read property 'q1' of undefined"

您能否说明如何将计算属性分组(或嵌套)到一个对象中?

我是否真的需要在我的示例中使用计算属性,以避免在下一个查询中未定义 formerResults?你能建议如何保持代码干净吗?

【问题讨论】:

【参考方案1】:

有几件事情需要考虑。

第一个问题:你能说出为什么在使用属性时逻辑会失败,并且可以使用计算属性吗?

data() 生命周期方法返回的属性在某种意义上是反应性的,每次更改它们时,Vue 都会触发新的渲染周期。但这并不意味着每个反应属性都会自动更新。你仍然需要更新它。所以,当你这样做时:

data() 
  return 
    queries : 
      q1 : 
        data: `$this.text + $this.formerResults` 
      
    ,

    formerResults : ''
  
,

Vue.js 尚未将这些反应属性添加到 this 实例。当然,此时this.formerResults 将是未定义的,this.queries.q1 会将其视为未定义。

为什么以及何时使用计算属性?

你是正确的使用计算属性。如果您需要自动建立依赖关系并且您不需要为某些属性设置setter(即自己设置值),那么您必须使用计算属性。

在您的情况下,查询 - q1q2 等必须在 formerResults 更改时自动更新。为此,您将使用计算属性。

如何将计算属性分组(或嵌套)到一个对象中?

您声明计算属性的方式是错误的,因此您会看到错误。 嵌套计算属性本身没有概念,但您可以创建一个单个复杂对象,它是多次计算的结果,并生成包含所有数据的单个值你需要:

computed: 
  queries: function () 
    return 
      q1:  data: `$this.text + $this.formerResults`,
      q2:  /* Some other stuff */,
      //... q3, q4, etc.
    ;
  

每次 textformerResults 被代码的某些部分更改时,您的 queries 对象将被重新计算。这样不会有任何性能损失。

我真的需要在我的示例中使用计算属性,以避免在下一个查询中未定义 formerResults 吗?你能建议如何保持代码干净吗?

使用计算属性是实现反应性的最简洁方式。在我看来,其他所有选择都很麻烦。例如,您可以使用 watchers 执行相同的操作,但它并不干净。

data() 
  return 
    queries: 
      q1:  data: '' ,
      // q2, q3, ...
    ,
    formerResults: ''
  
,
watch: 
  formerResults: function() 
    this.queries = 
      q1:  data: `$this.text + $this.formerResults` 
      // q2, q3, ...
    ;
  ,
  text: function() 
    this.queries = 
      q1:  data: `$this.text + $this.formerResults` 
      // q2, q3, ...
    ;
  

【讨论】:

非常感谢 Harshal 的简洁回答并展示了如何“嵌套”计算属性。只有一件事还不清楚:为什么formerResults 没有反应?我在time_1传递的参数textformerResults分别是一个字符串(作为prop传递)和一个空字符串''。查询结果存储在formerResults (vm.formerResults += /* add the results */),我想在time_2 和text 一起传递。那么为什么在 time_2 formerResults 被传递为 undefined 呢?你能澄清一下吗? @user305883 在评估q1 时,formerResults 本身是未定义的,当您开始累积结果时,undefined 会结转。此外,仅在 data 函数中定义依赖于 formerResultsq1 不会使 q1 反应。你仍然需要设置观察者。当 Vue.js 说它是响应式的时,这意味着每当 q1formerResults 发生变化时,模板都会再次呈现。这并不意味着当formerResults 更改时,会自动更新q1。为此,使用了计算属性。

以上是关于将计算属性嵌套在一个对象中以进行代码维护 (Vue)的主要内容,如果未能解决你的问题,请参考以下文章

Vue 无法更改嵌套 v-for 中的属性

Vue:访问错误对象中可能存在的嵌套属性的最佳方法

Vue.js 观察数组内的嵌套属性

Vue 计算属性

Vue 将对象作为计算属性传播

vue的计算和监视属性,附一小实例