【问题标题】:Can I insert a computed property into a Vue component dynamically我可以动态地将计算属性插入到 Vue 组件中吗
【发布时间】:2019-03-06 02:35:43
【问题描述】:

我通过迭代大量对象来生成 Vue 组件的内容。我想使用计算属性来确定是否显示某些节点​​,但由于计算引用在循环内使用,我需要能够动态设置引用名称。

下面是我正在尝试做的一个概念性示例。如何根据当前项目更改showItemX?

<template>
  <ul>
    <li v-for="item in myArr" v-if="showItemX">
      {{ item.name }}
    </li>
  </ul>
</template>
<script>
  export default {
    data() {
      return {
        myArr: [{
          id: 'item1',
          name: 'Item 1'
        }, {
          id: 'item2',
          name: 'Item 2'
        }]
      };
    },
    computed: {
      showItem1: function() {
        return this.$store.state.showItem1;
      },
      showItem2: function() {
        return this.$store.state.showItem2;
      }
    }
  }
</script>

2 种可能的解决方案

到目前为止,这是我考虑过的两条路线,但我不确定哪一条更有效,或者是否更喜欢另一种方式:

1。返回计算属性的单个对象

在此选项中,上面的两个计算属性将合并为一个属性:

computed: {
  showItem: function() {
    return {
      item1: this.$store.state.showItem1,
      item2: this.$store.state.showItem2
    }
  }
}

那么v-if 将被设置为showItem[item.id]:

<li v-for="item in myArr" v-if="showItem[item.id]">
  {{ item.name }}
</li>

这里的缺点是,每次依赖项之一发生变化时,似乎整个对象都会重新计算。

2。使用方法获取对应的计算属性

这里我尝试将item.id 传递给一个方法,作为访问相应计算属性的一种方式:

computed: {
  item1Show: function() {
    return this.$store.state.showItem1;
  },
  item2Show: function() {
    return this.$store.state.showItem2;
  }
},
methods: {
  showItem: function(id) {
    return this[id + 'Show']
  }
}

在模板中:

<li v-for="item in myArr" v-if="showItem(item.id)">
  {{ item.name }}
</li>

同样,在此示例中,我不确定我是否充分利用了计算属性。


是否应该优先选择这些选项中的一个,或者是否有更好的方法来完成我所缺少的?

【问题讨论】:

  • 我不知道这是否适用于你的情况,但也许stackoverflow.com/a/49032149/392102
  • @RoyJ 这让我想到了一个我没有考虑过的可能性。我想我可以使用单个计算属性为每个单独的项目创建一个子组件,该属性根据当前项目的 id 提供正确的逻辑。

标签: vue.js vuejs2 vue-component computed-properties


【解决方案1】:

关于 Vue 和 JavaScript 的好处是您可以使用适合您需要的任何方法,但是,我可能会发现以下内容最容易理解

<li v-for="item in myArr" v-if="showItem(item)">
    {{ item.name }}
</li>

然后定义showItem方法,例如

showItem(item) {
    return item.id === "item1" ?
        this.$store.state.showItem1 :
        this.$store.state.showItem2;
}

假设您没有在帖子中未显示的其他任何地方使用计算属性

【讨论】:

  • 我的例子被缩小了。我的数组中有大约 100 个项目,并且有几十个条件有时会考虑商店中的几个元素来确定是否显示每个项目。您的方法完全取消了计算属性,但这不会失去计算属性的缓存优势吗?我绝对可以将 switch/case 语句放入处理所有逻辑的方法中,但我认为使用计算道具会更好。
【解决方案2】:

有更好的方法。

对于可能的解决方案#1,你不妨这样做

<li v-for="(item, index) in myArr" v-if="$store.state['showItem' + (index + 1)]">

可能的解决方案 #2,您完全错过了 Vue 的优化。 该方法虽然不是计算密集型的,但每次渲染都会为每个元素重新运行。

以下是适合您示例问题的特定参数的解决方案。但是,这实际上并不是我在这里推荐的。更多内容如下。

<template>
      <ul>
        <!--
          `:key` is crucial for performance.
          otherwise, every element will re-render 
          whenever the filtered array updates.
        -->
        <li v-for="item in myFilteredArr" :key="item.id">
          {{ item.name }}
        </li>
      </ul>
</template>

<script>
  export default {
    data: _ => ({
      myArr: [
        {
          id: 'item1',
          name: 'Item 1'
        }, 
        {
          id: 'item2',
          name: 'Item 2'
        }
      ],
    }),

    computed: {
      myFilteredArr () {
        /* 
          abstracting state to a constant avoids 
          re-running the getter functions each iteration
        */
        const state = this.$store.state;
        return this.myArr.filter(
          (item, index) => state['showItem' + (index + 1)]
        );
      }
    }

  }
</script>

我的实际建议是将所有这些逻辑移到 Vuex getter 中。你可以在这里阅读它们:https://vuex.vuejs.org/guide/getters.html。

由于您的过滤逻辑已经在商店中处理,设置所有showItem的函数可以剪切并粘贴到Vuex getter中,以与上述相同的方式返回myFilteredArr。

这样,没有组件存储相互依赖,你的存储状态会更清晰。

【讨论】:

    猜你喜欢
    • 2018-07-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-11-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多