2.1节详细讲解了模板的基本语法,我们可以发现在模板中使用表达式是非常便利的,但是表达式更适用于简单运算,如果使用表达式来处理复杂的逻辑,则会让模板变得非常臃肿且难以维护。Vue为了帮助用户处理复杂的逻辑,提供了计算属性和监听,本节将会对计算属性进行讲解。
在2.1.1节的案例中,通过三目表达式动态判断data中score的值,从而决定显示的文本。这个动态判断的过程可以称为计算。这里将2.1.1节中三目表达式的模板编码单列出来,并对其进行分析。
上面的模板看起来有些复杂,可读性较差。而对于这段代码来说,更重要的是,如果页面中有多处需要同样的计算,这个计算的模板就需要重复编写多遍。
为了解决这一问题,Vue框架专门设计了一个重要语法:计算属性。当模板显示的某个数据需要通过已有数据进行一定的逻辑计算才能确定时,就可以选择用计算属性语法来实现。先来看利用计算属性语法重构后的代码,具体如下。
对比2.1.1节中的代码,可以明显地看出,在重构的代码中多出一个配置对象computed。实际上这就是Vue中计算属性定义的位置,整个代理对象需要的计算属性都需要定义在computed配置对象中。
我们结合上面这段代码来分析,“测评得分”的数据就是在读取data数据,这并没有什么特别的,我们不对其多做讲解。“测评结果”需要根据“测评得分”来显示对应的结果,该结果需要根据score的数据来决定,这满足了计算属性的条件,因此使用了计算属性来实现。这里在computed配置对象中定义了名称为resultText的计算属性,它本质上就是一个函数,内部可以根据已有的data数据进行计算,产生要显示的结果数据并返回它。需要注意的是,计算属性函数中的this就是当前组件对象,通过它可以直接访问data中的数据。在模板中可以读取计算属性函数resultText,当初始化显示时,系统会自动调用这个计算属性函数得到返回值并显示到页面上。
此时,data中score的值为59,因此返回的“测评结果”为“入学测试未通过,暂时不可以来尚硅谷学习”。页面效果如图2-7所示。
图2-7 页面效果
如果更新了计算属性依赖的数据会怎么样呢?
比如我们更新了data中的score,那么计算属性函数resultText会重新执行计算并返回新的结果值,对应的页面元素会自动更新。下面通过代码对其进行测试。
我们为其增加了一个按钮“学习一段时间后重新测评”,当点击该按钮更新score的值后,h2标签中的内容也会被更新。同时计算属性函数resultText重新执行返回新的值,h3标签也显示为最新的计算属性值,如图2-8和图2-9所示。这里需要注意的是,每次更新依赖数据,计算属性函数都会重新执行计算。
图2-8 点击按钮前
图2-9 点击按钮后
2.2.1节中计算属性的效果还可以通过在模板中调用method方法实现,它的实现结果与计算属性是一样的。
下面通过在模板中调用method方法来实现2.2.1节中测评结果的功能。
模板代码片段如下。
methods代码片段如下。
无论是初始化显示还是更新显示,其效果跟计算属性的效果都是一样的。尽管如此,我们在开发时还是会选择使用计算属性来实现。这是因为计算属性内会将计算属性函数返回的结果数据进行缓存处理,如果结果数据需要在页面中显示多次,那么计算属性函数只会执行1次,但method方法会对应执行多次。这样对比下来,计算属性的效率明显要比方法高。
下面修改一下模板,对计算属性和method方法再次进行测试。
当页面初始化显示时,计算属性函数只执行了1次,而method方法执行了3次。点击按钮更新,计算属性函数只执行了1次,而method方法执行了3次。因此当有可能存在结果数据需要显示多次的情况时,明显应该选择计算属性,因为其效率更高,但如果确定只显示一次,则method方法也是一个可以接受的选择。
计算属性在默认情况下仅能通过计算属性函数得出结果。当开发者尝试修改一个计算属性时,会收到一个运行时警告提示。我们来看如图2-10所示的页面效果。
图2-10 页面效果
现有3个需求,具体如下。
①姓名由“姓-名”组成,姓名的初始显示为“A-B”。
②当改变姓或名时,姓名能自动同步变化。
③姓和名能实时与姓名同步。
下面对数据进行分析和设计。可以将“姓”和“名”设计为2个data数据,我们可以利用v-model实现双向数据绑定,但因为“姓名”是由“姓”和“名”动态确定的,所以我们可以将“姓名”设计为计算属性,同样用v-model绑定到input标签上。具体实现代码如下。
在上面的代码中,我们在data对象中定义了firstName和lastName两个计算属性,在computed配置中定义了计算属性fullName,并通过v-model将其绑定到对应的input标签上。初始显示实现了需求①中“姓名”的显示要求,如图2-11所示;当修改“姓”或“名”的内容时,“姓名”也会自动同步变化,这样也实现了需求②中“姓名”同步变化的要求,如图2-12所示。
图2-11 初始显示
图2-12 数据同步改变
那么问题来了,当我们在输入框(input)中改变“姓名”的内容时,v-model会自动将输入值赋给计算属性fullName,Vue框架会抛出警告提示,如图2-13所示。
图2-13 抛出警告提示
警告提示表示写操作失败,因为计算属性fullName是只读的,也就是只能计算返回一个值。那么应该如何设置计算属性值呢?答案是:可以通过同时提供getter和setter的计算属性来实现。下面修改一下计算属性fullName的实现,代码如下。
此时的计算属性fullName是一个对象,包含get方法(常称为getter)和set方法(常称为setter)。前面写的计算属性函数的功能等同于get方法,当它在初始化时会执行一次,并且任意依赖数据发生变化时会再次执行,也就实现了“姓名”的初始动态显示与修改“姓”或“名”的内容时会同步更新显示的功能。而set方法则是在修改fullName属性值后,会自动执行。也就是说,当修改“姓名”的内容时,计算属性的set方法就会自动执行,在set方法中接收fullName指定的最新值,并分隔出两个值的数组分别去更新firstName和lastName,这样就实现了需求③中的要求。