Vue.js中方法和计算值的主要区别是什么?

在我看来,它们是一样的,是可以互换的。


当前回答

来自文档

..计算属性是基于它们的依赖项缓存的。计算属性只有在其某些依赖项发生更改时才会重新计算。

如果您希望缓存数据,请使用Computed属性,另一方面,如果您不想缓存数据,请使用简单的Method属性。

其他回答

我会尽量补充其他成员的回答。这个例子和解释让我完全掌握了计算属性的要点。我希望在看完我的文章后,你也能意识到这一点。


如果需要更改数据,则必须使用方法。当您需要更改现有数据的表示时,您将使用计算属性。当您练习这两个概念时,您将轻松地使用它们。以下是一些奇特的钥匙:

计算属性必须总是返回一个值; 计算属性仅用于转换数据,而不是用于改变我们的表示层|,它们不应该改变或改变现有的数据。

由于您已经阅读了它或在运行我的示例代码之后,您将看到只有在计算属性中显示的值被更改(在方法中或通过用户输入或其他方式),计算属性将被重新计算并缓存。 但是每次调用一个方法时,不管结果如何,它都会被执行(例如,在我的例子中,当一个值达到0时,计算的属性不再被重新计算)

在这个例子中,有一个简单的系统;你有:

自己的现金; 你银行账户里的现金; 可从您的银行帐户提款; 有可能从某人那里借一些钱(无限的钱)。

new Vue({ el: '#app', data: { infinity: Infinity, value: 3, debt: -6, cash: 9, moneyInBank: 15, }, computed: { computedPropRemainingCashFundsIfPaid: function() { console.log('computedPropRemainingCashFundsIfPaid'); return this.debt + this.cash; }, computedPropRemainingTotalFunds: function() { console.log('computedPropRemainingTotalFunds'); return this.cash + this.moneyInBank + this.debt; } }, methods: { depositFunds: function(from, to, value, limit = false) { if (limit && (this[to] + value) >= 0) { // if you try to return greater value than you owe this[from] += this[to]; this[to] = 0; } else if (this[from] > value && this[from] - value >= 0) { // usual deposit this[to] += value; this[from] -= value; } else { // attempt to depost more than you have this[to] += this[from]; this[from] = 0; } }, repayADebt: function() { this.value = Math.abs(this.value); if (this.debt < 0) { this.depositFunds('cash', 'debt', this.value, true); } console.log('Attempt to repayADebt', this.value); }, lendAmount: function() { this.depositFunds('infinity', 'debt', -Math.abs(this.value)); console.log('Attempt to lendAmount', this.value); }, withdraw: function() { if (this.moneyInBank) { this.depositFunds('moneyInBank', 'cash', this.value); } console.log('Attempt to withdraw', this.value); } } }); * { box-sizing: border-box; padding: 0; margin: 0; overflow-wrap: break-word; } html { font-family: "Segoe UI", Tahoma, Geneva, Verdana; font-size: 62.5%; } body { margin: 0; font-size: 1.6rem; } #app { margin: 3rem auto; max-width: 50vw; padding: 1rem; box-shadow: 0 2px 8px rgba(0, 0, 0, 0.26); } label, input { margin-bottom: 0.5rem; display: block; width: 100%; } label { font-weight: bold; } ul { list-style: none; margin: 1rem 0; padding: 0; } li { margin: 1rem 0; padding: 1rem; border: 1px solid #ccc; } .grid { display: grid; grid: 1fr / 1fr min-content 1fr min-content; gap: 1rem; align-items: center; margin-bottom: 1rem; } .grid> :is(button, input) { height: 3rem; margin: 0; } .computed-property-desc { padding: 1rem; background-color: rgba(0, 0, 0, 0.3); text-align: justify; } <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>A First App</title> <link rel="stylesheet" href="styles.css" /> </head> <body> <div id="app"> <h1>Computed Properties Guide</h1> <p style="background-color: bisque;"> Let's assume that you have <span v-once>{{ cash }}</span>$; And you need to pay a debt=<span v-once>{{ debt }}</span> </p> <p>Your bank account: {{ moneyInBank }}$ <button v-on:click="withdraw(value)">Withdrow {{ value }}$ from bank</button></p> <p>Your cash: {{ cash }}$</p> <p>Your debt: {{ debt }}$ <button v-on:click="lendAmount(value)">Lend {{ value }}$ from Infinity</button></p> <div class="grid"> <button v-on:click="repayADebt(value)">Repay a debt</button> <span>in amout of</span> <input type="text" v-model.number="value"> <span>$</span> </div> <p>computedPropRemainingCashFundsIfPaid/<br><mark>Available funds in case of debt repayment</mark> = {{ computedPropRemainingCashFundsIfPaid }}$</p> <p>computedPropRemainingTotalFunds = {{ computedPropRemainingTotalFunds }}$</p> <p class="computed-property-desc">when you need to change data, you will use methods. And When you need to change the presentation of existing data, you will use computed properties. As you practice both concepts, it will become easier which one should you use. Very important notes: 1. it must always return a value; 2. computed properties are only used for transforming data and not for chaning it for our presentation layer | they should not alter or change the existing data</p> </div> <script src="https://cdn.jsdelivr.net/npm/vue@2.6.12/dist/vue.js"></script> </body> </html>

下面是这个问题的详细分析。

何时使用方法

对DOM中发生的事件做出反应 在组件中发生事情时调用函数。 可以从计算属性或观察器调用方法。

何时使用计算属性

您需要从现有数据源组合新数据 在模板中使用的变量是由一个或多个数据属性构建的 您希望将复杂的、嵌套的属性名称简化为更易于阅读和使用的名称(但在原始属性更改时更新它) 您需要从模板引用一个值。在这种情况下,创建计算属性是最好的,因为它是缓存的。 您需要侦听多个数据属性的更改

计算属性

计算属性也称为计算值。这意味着,它们可以随时更新和更改。此外,它还缓存数据,直到数据发生更改。在实例化Vue时,计算属性将转换为属性。

还有一件事我想分享,你不能在计算属性中传递任何参数,这就是为什么在调用任何计算机属性时不需要括号。

方法

方法与函数相同,以相同的方式工作。此外,除非调用方法,否则方法什么也不做。此外,像所有javascript函数一样,它接受参数,并且每次调用时都会重新计算。之后,它们就不能缓存值了

在方法中调用圆括号,你可以发送一个或多个参数。

@gleenk需要一个实际的例子来说明方法和计算属性之间的缓存和依赖关系的差异,我将展示一个简单的场景:

app.js

new Vue({
    el: '#vue-app',
    data: {
        a: 0,
        b: 0,
        age: 20
    },
    methods: {
        addToAmethod: function(){
            console.log('addToAmethod');
            return this.a + this.age;
        },
        addToBmethod: function(){
            console.log('addToBmethod');
            return this.b + this.age;
        }
    },
    computed: {
        addToAcomputed: function(){
            console.log('addToAcomputed');
            return this.a + this.age;
        },
        addToBcomputed: function(){
            console.log('addToBcomputed');
            return this.b + this.age;
        }
    }
});

Here we have 2 methods and 2 computed properties that perform the same task. The methods addToAmethod & addToBmethod and the computed properties addToAcomputed & addToBcomputed all add +20 (i.e. the age value) to either a or b. Regarding the methods, they are both called every time an action has been performed on any of the listed properties, even if the dependencies for one specific method have not changed. For the computed properties, the code is executed only when a dependency has changed; for example, one of the specific property values that refers to A or B will trigger addToAcomputed or addToBcomputed, respectively.

方法和计算描述看起来非常相似,但正如@Abdullah Khan已经指定的那样,它们不是一回事!现在让我们尝试添加一些html来一起执行所有内容,看看有什么不同。

方法案例演示

new Vue({ el: '#vue-app', data: { a: 0, b: 0, age: 20 }, methods: { addToAmethod: function(){ console.log('addToAmethod'); return this.a + this.age; }, addToBmethod: function(){ console.log('addToBmethod'); return this.b + this.age; } } }); <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>VueJS Methods - stackoverflow</title> <link href="style.css" rel="stylesheet" /> <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.11/vue.min.js"></script> </head> <body> <div id="vue-app"> <h1>Methods</h1> <button v-on:click="a++">Add to A</button> <button v-on:click="b++">Add to B</button> <p>Age + A = {{ addToAmethod() }}</p> <p>Age + B = {{ addToBmethod() }}</p> </div> </body> <script src="app.js"></script> </html>

解释结果

When I click on the button "Add to A", all the methods are called (see the console log screen result above), the addToBmethod() is also executed but I didn't press the "Add to B" button; the property value that refers to B has not changed. The same behaviour comes if we decide to click the button "Add to B", because again both the methods will be called independently of dependency changes. According to this scenario this is bad practice because we are executing the methods every time, even when dependencies have not changed. This is really resource consuming because there is not a cache for property values that have not changed.

Computed属性案例演示

new Vue({ el: '#vue-app', data: { a: 0, b: 0, age: 20 }, computed: { addToAcomputed: function(){ console.log('addToAcomputed'); return this.a + this.age; }, addToBcomputed: function(){ console.log('addToBcomputed'); return this.b + this.age; } } }); <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>VueJS Computed properties - stackoverflow</title> <link href="style.css" rel="stylesheet" /> <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.11/vue.min.js"></script> </head> <body> <div id="vue-app"> <h1>Computed Properties</h1> <button v-on:click="a++">Add to A</button> <button v-on:click="b++">Add to B</button> <p>Age + A = {{ addToAcomputed }}</p> <p>Age + B = {{ addToBcomputed }}</p> </div> </body> <script src="app.js"></script> </html>

解释结果

When I click on the button "Add to A", only the computed property addToAcomputed is called because, as we already said, the computed properties are executed only when a dependency has changed. And since I didn't press the button "Add to B" and the age property value for B has not changed, there is no reason to call and execute the computed property addToBcomputed. So, in a certain sense, the computed property is maintaining the "same unchanged" value for the B property like a kind of cache. And in this circumstance this is consider good practice.

在vue 3附带的vue组合API中,可以作为vue 2的插件使用,方法和计算属性是不同的语法:

例子:

计算:

它是一个默认接受getter回调作为参数的函数,并根据其他属性(如ref, reactive或store state)返回一个不可变的ref。

import {computed,ref} from 'vue'

export default{

setup(){
  const count=ref(0);
  
  const doubleCount=computed(()=>count.value*2) 

 return {count,doubleCount} //expose the properties to the template 
 }
}

方法

它们是纯javascript函数,在Vue和vanilla js中以相同的方式表现,它们暴露在模板中并用作事件处理程序,它们不应该用于渲染目的,这可能会导致一些问题,如无限渲染。

import {computed,ref} from 'vue'

export default{

setup(){
  const count=ref(0);
  
  const doubleCount=computed(()=>count.value*2) 
 
  function increment(){
   ref.value++
 }

 return {count,doubleCount,increment} //expose the properties/functions to the template 
 }
}

区别在于:

计算:

它被计算为不可变属性,而不是函数 它观察另一个属性并基于该属性返回一个属性。 它不能带参数。 可以使用watch属性观看它

方法:

用于重构computed/watcher属性或其他函数中的代码 用作事件处理程序 为了避免呈现问题,不应该在模板中调用它。