我可以在 Vue.Js 中的计算属性中传递参数吗?

Can I pass parameters in computed properties in Vue.Js

本文关键字:参数 属性 计算 Vue Js 我可以      更新时间:2023-09-26

是否可以在 Vue.Js 中的计算属性中传递参数。我可以看到当使用计算的 getter/setter 时,他们可以获取一个参数并将其分配给一个变量。就像文档中的这里一样:

computed: {
  fullName: {
    // getter
    get: function () {
      return this.firstName + ' ' + this.lastName
    },
    // setter
    set: function (newValue) {
      var names = newValue.split(' ')
  
      this.firstName = names[0]
      this.lastName = names[names.length - 1]
    }
  }
}

这是否也有可能:

computed: {
  fullName: function (salut) {
    return salut + ' ' + this.firstName + ' ' + this.lastName    
  }
}

其中,计算属性接受参数并返回所需的输出。但是,当我尝试此操作时,我收到此错误:

vue.common.js:2250 未捕获的类型错误:全名不是一个函数(...(

在这种情况下,我应该使用方法吗?

很可能

你想使用一个方法

<span>{{ fullName('Hi') }}</span>
methods: {
  fullName(salut) {
      return `${salut} ${this.firstName} ${this.lastName}`
  }
}
<小时 />

更长的解释

从技术上讲,您可以将计算属性与如下参数一起使用:

computed: {
   fullName() {
      return salut => `${salut} ${this.firstName} ${this.lastName}`
   }
}

(感谢Unirgy提供基本代码。

计算属性

和方法之间的区别在于,计算属性是缓存的,并且仅在其依赖项更改时更改。方法将在每次调用时进行评估

如果需要参数,在这种情况下,使用计算属性函数通常比使用方法没有任何好处。虽然它允许你将参数化的 getter 函数绑定到 Vue 实例,但你会失去缓存,所以那里没有任何好处,事实上,你可能会破坏反应性 (AFAIU(。你可以在 Vue 文档中阅读更多关于这一点的信息 https://v2.vuejs.org/v2/guide/computed.html#Computed-Caching-vs-Methods

唯一有用的情况是当您必须使用吸气剂并需要对其进行参数化时。例如,这种情况发生在 Vuex 中。在 Vuex 中,这是从存储中同步获取参数化结果的唯一方法(操作是异步的(。因此,这种方法被官方 Vuex 文档列为其 getter。https://vuex.vuejs.org/guide/getters.html#method-style-access

您可以使用方法,但我更喜欢使用计算属性而不是方法,如果它们没有改变数据或没有外部影响。

你可以通过这种方式将参数传递给计算属性(没有记录,但维护者建议,不记得在哪里(:

computed: {
   fullName: function () {
      var vm = this;
      return function (salut) {
          return salut + ' ' + vm.firstName + ' ' + vm.lastName;  
      };
   }
}

请不要使用此解决方案,它只会使代码复杂化而没有任何好处。

好吧,从技术上讲,我们可以将参数传递给计算函数,就像我们可以将参数传递给 vuex 中的 getter 函数一样。这样的函数是返回函数的函数。

例如,在商店的获取者中:

{
  itemById: function(state) {
    return (id) => state.itemPool[id];
  }
}

这个 getter 可以映射到组件的计算函数:

computed: {
  ...mapGetters([
    'ids',
    'itemById'
  ])
}

我们可以在模板中使用此计算函数,如下所示:

<div v-for="id in ids" :key="id">{{itemById(id).description}}</div>

我们可以应用相同的方法来创建一个接受参数的计算方法。

computed: {
  ...mapGetters([
    'ids',
    'itemById'
  ]),
  descriptionById: function() {
    return (id) => this.itemById(id).description;
  }
}

并在我们的模板中使用它:

<div v-for="id in ids" :key="id">{{descriptionById(id)}}</div>

话虽如此,我并不是说这是使用 Vue 做事的正确方式。

但是,我可以观察到,当具有指定 ID 的项目在存储中发生突变时,视图确实会使用此项目的新属性自动刷新其内容(绑定似乎工作正常(。

computed: {
  fullName: (app)=> (salut)=> {
      return salut + ' ' + app.firstName + ' ' + app.lastName    
  }
}

当您想要使用时

<p>{{fullName('your salut')}}</p>

[Vue2] 过滤器是 Vue 组件提供的一项功能,可让您将格式和转换应用于模板动态数据的任何部分。

它们不会更改组件的数据或任何内容,但只会影响输出。

假设您正在打印一个名称:

new Vue({
  el: '#container',
  data() {
    return {
      name: 'Maria',
      lastname: 'Silva'
    }
  },
  filters: {
    prepend: (name, lastname, prefix) => {
      return `${prefix} ${name} ${lastname}`
    }
  }
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="container">
  <p>{{ name, lastname | prepend('Hello') }}!</p>
</div>

请注意应用筛选器的语法,即 | filterName。如果您熟悉 Unix,那就是 Unix 管道运算符,它用于将操作的输出作为输入传递给下一个操作。

组件的 filters 属性是一个对象。单个筛选器是接受一个值并返回另一个值的函数。

返回的值是实际打印在 Vue.js 模板中的值。

过滤器在 Vue3 中被删除

你可以传递参数,但要么它不是 vue.js 方式,要么你这样做的方式是错误的。

但是,在某些情况下,您需要这样做。我将向您展示一个简单的示例,使用 getter 和 setter 将值传递给计算属性。

<template>
    <div>
        Your name is {{get_name}} <!-- John Doe at the beginning -->
        <button @click="name = 'Roland'">Change it</button>
    </div>
</template>

和剧本

export default {
    data: () => ({
        name: 'John Doe'
    }),
    computed:{
        get_name: {
            get () {
                return this.name
            },
            set (new_name) {
                this.name = new_name
            }
        },
    }    
}

单击按钮时,我们将名称"Roland"传递给计算属性,set()我们将名称从"John Doe"更改为"Roland"。

下面是计算与 getter 和 setter 一起使用的常见用例。假设你有以下 vuex 商店:

export default new Vuex.Store({
  state: {
    name: 'John Doe'
  },
  getters: {
    get_name: state => state.name
  },
  mutations: {
    set_name: (state, payload) => state.name = payload
  },
})

在你的组件中,你想v-model添加到输入中,但使用 vuex 存储。

<template>
    <div>
        <input type="text" v-model="get_name">
        {{get_name}}
    </div>
</template>
<script>
export default {
    computed:{
        get_name: {
            get () {
                return this.$store.getters.get_name
            },
            set (new_name) {
                this.$store.commit('set_name', new_name)
            }
        },
    }    
}
</script>

您还可以通过返回函数将参数传递给 getter。当您要查询存储中的数组时,这特别有用:

getters: {
  // ...
  getTodoById: (state) => (id) => {
    return state.todos.find(todo => todo.id === id)
  }
}
store.getters.getTodoById(2) // -> { id: 2, text: '...', done: false }

请注意,每次调用通过方法访问的 getter 时都会运行它们,并且不会缓存结果。

这被称为方法式访问,它记录在 Vue.js 文档中。

我想首先重申前面的警告,将计算(已缓存(与参数一起使用只会使计算不缓存,实际上只是使其成为一种方法。

但是,话虽如此,以下是我能想到的所有变体,这些变体可能有边缘情况可供使用。 如果您将其剪切并粘贴到演示应用程序中,则应该清楚发生了什么:

<template>
  <div>
    <div style="background: violet;"> someData, regularComputed: {{ someData }}, {{ regularComputed }} </div>
    <div style="background: cornflowerblue;"> someComputedWithParameterOneLine: {{ someComputedWithParameterOneLine('hello') }} </div>
    <div style="background: lightgreen;"> someComputedWithParameterMultiLine: {{ someComputedWithParameterMultiLine('Yo') }} </div>
    <div style="background: yellow"> someComputedUsingGetterSetterWithParameterMultiLine: {{ someComputedUsingGetterSetterWithParameterMultiLine('Tadah!') }} </div>
    <div>
      <div style="background: orangered;"> inputData: {{ inputData }} </div>
      <input v-model="inputData" />
      <button @click="someComputedUsingGetterSetterWithParameterMultiLine = inputData">
        Update 'someComputedUsingGetterSetterWithParameterMultiLine' with 'inputData'.
      </button>
    </div>
    <div style="background: red"> newConcatenatedString: {{ newConcatenatedString }} </div>
  </div>
</template>
<script>
  export default {
    data() {
      return {
        someData: 'yo',
        inputData: '',
        newConcatenatedString: ''
      }
    },
    computed: {
      regularComputed(){
        return 'dude.'
      },
      someComputedWithParameterOneLine(){
        return (theParam) => `The following is the Parameter from *One* Line Arrow Function >>> ${theParam}`
      },
      someComputedWithParameterMultiLine(){
        return (theParam) => {
          return `The following is the Parameter from *Multi* Line Arrow Function >>> ${theParam}`
        }
      },
      // NOTICE that Computed with GETTER/SETTER is now an Object, that has 2 methods, get() and set(), so after the name of the computed we use : instead of ()
      // thus we do: "someComputedUsingGetterSetterWithParameterMultiLine: {...}" NOT "someComputedUsingGetterSetterWithParameterMultiLine(){...}"
      someComputedUsingGetterSetterWithParameterMultiLine: {
        get () {
          return (theParam) => {
            return `As part of the computed GETTER/SETTER, the following is inside get() which receives a Parameter (using a multi-line Arrow Function) >>> ${theParam}`
          }
        },
        set(newSetValue) {
          console.log('Accessing get() from within the set()', this.someComputedUsingGetterSetterWithParameterMultiLine('hello from inside the Setter, using the Getter.'))
          console.log('Accessing newSetValue in set() >>>>', JSON.stringify(newSetValue))
          this.newConcatenatedString = `**(1)${this.someComputedUsingGetterSetterWithParameterMultiLine('hello from inside the Setter, using the Getter.')}**  This is a concatenation of get() value that had a Parameter, with newSetValue **(2)${newSetValue}** that came into the set().`
        }
      },
    },
  }
</script>
我没有

看到 Vue3 和/或使用组合 API 的答案,所以这是我的一点(因为我总是忘记如何做到这一点(。

您可以通过将参数包装在另一个函数中来使计算接受参数,如下所示:

const firstName = ref("John");
const lastName = ref("Doe");
const fullName = (salut: string) =>
  computed(() =>
    `${salut} ${firstName.value} ${lastName.value}`);
<小时 />

如果要使用 Pinia(将参数传递给 getter(进行状态管理,则可以将其计算用作 getter:

// In component's setup function
const store = useStore();
const fullName = store.fullName("Hello"); // ComputedRef<string> 
console.log(fullName) // "Hello John Doe"

计算可以被视为一个函数。因此,对于validation的示例,您可以清楚地执行以下操作:

    methods: {
        validation(attr){
            switch(attr) {
                case 'email':
                    const re = /^(([^<>()'[']'.,;:'s@'"]+('.[^<>()'[']'.,;:'s@'"]+)*)|('".+'"))@(([^<>()[']'.,;:'s@'"]+'.)+[^<>()[']'.,;:'s@'"]{2,})$/i;
                    return re.test(this.form.email);
                case 'password':
                    return this.form.password.length > 4
            }
        },
        ...
    }

您将像这样使用:

  <b-form-input
            id="email"
            v-model="form.email"
            type="email"
            :state="validation('email')"
            required
            placeholder="Enter email"
    ></b-form-input>

请记住,您仍然会错过特定于computed的缓存。

是的,可以使用参数的方法。与上述答案一样,在您的示例中,最好使用方法,因为执行非常轻。

仅供参考,在方法复杂且成本高的情况下,您可以像这样缓存结果:

data() {
    return {
        fullNameCache:{}
    };
}
methods: {
    fullName(salut) {
        if (!this.fullNameCache[salut]) {
            this.fullNameCache[salut] = salut + ' ' + this.firstName + ' ' + this.lastName;
        }
        return this.fullNameCache[salut];
    }
}

注意:使用此功能时,如果处理数千个,请注意内存

您需要

小心vue/no-side-effects-in-computed-properties ESlint 规则,不要在 computed 内部进行任何操作。

同时,如果您希望采用一种记忆方法,您可以阅读本文或 Vueuse 的useMemoize

甚至从 Vue3.2 开始v-memo

我没有看到一个清晰的 Vue 3 示例,所以我正在从我处理的应用程序添加一个。首先调用一个方法,该方法随后返回计算值。因此,当 Vue 重新渲染时将调用该方法,但随后返回缓存的计算值,并且仅在反应式输入变量更改时才执行。

<script setup>
import { computed, ref } from 'vue'
const itemOne = ref(1);
const itemTwo = ref(2);
const getItemDoubled: (key) => {
    return computed(()=> item[key].value * 2);
}
</script>
<template>
    <p>get dynamic name computed value: {{ getItemDoubled('One') }}
    <p>get dynamic name computed value: {{ getItemDoubled('Two') }}
</template