我可以在 Vue.Js 的计算属性中传递参数吗
Can I pass parameters in computed properties in Vue.Js
是否可以在 Vue.Js 的计算属性中传递参数。我可以看到当 getters/setter 使用 computed 时,他们可以获取一个参数并将其分配给一个变量。像这里来自 documentation:
// ...
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 属性 采用参数和 returns 所需的输出。然而,当我尝试这个时,我收到了这个错误:
vue.common.js:2250 Uncaught TypeError: fullName is not a function(…)
我应该在这种情况下使用方法吗?
很可能您想使用一种方法
<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://vuejs.org/v2/guide/computed.html#Computed-Caching-vs-Methods
唯一有用的情况是您必须使用getter并且需要对其进行参数化。例如,这种情况发生在 Vuex 中。在 Vuex 中,这是从商店同步获取参数化结果的唯一方法(操作是异步的)。因此,官方 Vuex 文档列出了这种方法的 getters
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;
};
}
}
编辑:请不要使用此解决方案,它只会使代码复杂化而没有任何好处。
是的,有使用参数的方法。就像上面提到的答案一样,在你的例子中最好使用方法,因为执行很轻。
仅供参考,在方法复杂成本高的情况下,可以这样缓存结果:
data() {
return {
fullNameCache:{}
};
}
methods: {
fullName(salut) {
if (!this.fullNameCache[salut]) {
this.fullNameCache[salut] = salut + ' ' + this.firstName + ' ' + this.lastName;
}
return this.fullNameCache[salut];
}
}
注意:使用这个的时候,如果处理上千个,注意内存
好吧,从技术上讲,我们可以将参数传递给计算函数,就像我们可以将参数传递给 vuex 中的 getter 函数一样。这样的函数就是returns一个函数
的函数
例如,在商店的 getters 中:
{
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 的项目在商店中发生变化时,视图会使用该项目的新属性自动刷新其内容(绑定似乎工作正常)。
You can pass parameters but either it is not a vue.js way or the way you are doing is wrong.
但是有些情况下您需要这样做 so.I 我将向您展示一个使用 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 会在您每次调用它们时 运行,并且不会缓存结果。
这称为方法式访问,它 is documented on the Vue.js docs。
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>
注意应用过滤器的语法,即 |过滤器名称。如果您熟悉 Unix,那就是 Unix 管道运算符,它用于将一个操作的输出作为输入传递给下一个操作。
组件的过滤器属性是一个对象。
单个过滤器是接受一个值和 returns 另一个值的函数。
返回值是 Vue.js 模板中实际打印的值。
Filters were removed in 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
的缓存。
我想首先重申之前的警告,即使用带有参数的计算(已缓存)只会使计算不被缓存,实际上只是使它成为一种方法。
然而,话虽这么说,这里是我能想到的所有变体,它们可能有使用的边缘情况。如果您将其剪切并粘贴到演示应用程序中,应该清楚发生了什么:
<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.Js 的计算属性中传递参数。我可以看到当 getters/setter 使用 computed 时,他们可以获取一个参数并将其分配给一个变量。像这里来自 documentation:
// ...
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 属性 采用参数和 returns 所需的输出。然而,当我尝试这个时,我收到了这个错误:
vue.common.js:2250 Uncaught TypeError: fullName is not a function(…)
我应该在这种情况下使用方法吗?
很可能您想使用一种方法
<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://vuejs.org/v2/guide/computed.html#Computed-Caching-vs-Methods
唯一有用的情况是您必须使用getter并且需要对其进行参数化。例如,这种情况发生在 Vuex 中。在 Vuex 中,这是从商店同步获取参数化结果的唯一方法(操作是异步的)。因此,官方 Vuex 文档列出了这种方法的 getters 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;
};
}
}
编辑:请不要使用此解决方案,它只会使代码复杂化而没有任何好处。
是的,有使用参数的方法。就像上面提到的答案一样,在你的例子中最好使用方法,因为执行很轻。
仅供参考,在方法复杂成本高的情况下,可以这样缓存结果:
data() {
return {
fullNameCache:{}
};
}
methods: {
fullName(salut) {
if (!this.fullNameCache[salut]) {
this.fullNameCache[salut] = salut + ' ' + this.firstName + ' ' + this.lastName;
}
return this.fullNameCache[salut];
}
}
注意:使用这个的时候,如果处理上千个,注意内存
好吧,从技术上讲,我们可以将参数传递给计算函数,就像我们可以将参数传递给 vuex 中的 getter 函数一样。这样的函数就是returns一个函数
的函数例如,在商店的 getters 中:
{
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 的项目在商店中发生变化时,视图会使用该项目的新属性自动刷新其内容(绑定似乎工作正常)。
You can pass parameters but either it is not a vue.js way or the way you are doing is wrong.
但是有些情况下您需要这样做 so.I 我将向您展示一个使用 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 会在您每次调用它们时 运行,并且不会缓存结果。
这称为方法式访问,它 is documented on the Vue.js docs。
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>
注意应用过滤器的语法,即 |过滤器名称。如果您熟悉 Unix,那就是 Unix 管道运算符,它用于将一个操作的输出作为输入传递给下一个操作。
组件的过滤器属性是一个对象。 单个过滤器是接受一个值和 returns 另一个值的函数。
返回值是 Vue.js 模板中实际打印的值。
Filters were removed in 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
的缓存。
我想首先重申之前的警告,即使用带有参数的计算(已缓存)只会使计算不被缓存,实际上只是使它成为一种方法。
然而,话虽这么说,这里是我能想到的所有变体,它们可能有使用的边缘情况。如果您将其剪切并粘贴到演示应用程序中,应该清楚发生了什么:
<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>