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

是否有可能在Vue.Js中传递计算属性中的参数。我可以看到,当有getter /setter使用computed时,他们可以接受一个参数并将其分配给一个变量。比如这里来自文档:

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
}
}

其中computed属性接受一个参数并返回所需的输出。然而,当我尝试这样做时,我得到这个错误:

vue.common.js:2250 Uncaught TypeError: fullName不是函数(…)

我是否应该在这种情况下使用方法?

326875 次浏览

最可能的情况是使用方法

<span>\{\{ fullName('Hi') }}</span>


methods: {
fullName(salut) {
return `${salut} ${this.firstName} ${this.lastName}`
}
}

更详细的解释

从技术上讲,你可以像这样使用一个带有参数的computed属性:

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中了解更多

唯一有用的情况是当你必须使用一个getter并且需要参数化它。例如,这种情况发生在Vuex中。在Vuex中,这是从存储中同步获取参数化结果的唯一方法(操作是异步的)。因此,官方Vuex文档列出了这种方法的getter https://vuex.vuejs.org/guide/getters.html#method-style-access < / p >

您可以使用方法,但我仍然倾向于使用计算属性而不是方法,如果它们不会改变数据或没有外部影响的话。

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

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

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

是的方法是用来使用参数的。就像上面的答案一样,在你的例子中,最好使用方法,因为执行非常轻。

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

data() {
return {
fullNameCache:{}
};
}


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

注意:使用此方法时,如果处理的是数千,请注意内存

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

例如,在存储的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的项在存储中发生变化时,视图确实会使用该项的新属性自动刷新其内容(绑定似乎工作得很好)。

你可以传递参数,但这不是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文档中记录了什么

computed: {
fullName: (app)=> (salut)=> {
return salut + ' ' + this.firstName + ' ' + this.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中删除了过滤器

Computed可以被认为是一个函数。因此,对于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的缓存。

我想首先重申前面的警告,使用computed(被缓存的)参数只会使computed不被缓存,实际上只是使它成为一个方法。

然而,话虽如此,这里是我能想到的所有可能有边界情况的变化。如果你剪&将其粘贴到演示应用程序中,这样就可以清楚地看到发生了什么:

<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>

我没有看到一个清晰的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

你需要小心vue/no-side-effects-in-computed-properties ESlint规则,不要在computed里面做任何东西。

同时,如果你正在寻找一种记忆类型的方法,你可以给这篇文章useMemoize from Vueuse一个read。

甚至从Vue3.2开始v-memo