1 computed计算属性
上一章我们提到指令的一般格式是:
指令名name[:参数arg][.修饰符modifiers][=表达式expression]
其中表达式expression会在其所属实例作用域下作为js代码被解析。前面我在v-on事件监听时,也提到过事件的处理有3种方式:
- 将js代码加在指令的表达式中
- 将事件的处理逻辑封装到方法中,把方法与事件绑定起来
- 在表达式中使用内敛语句调用方法
这3种方式会在绑定元素所属的实例作用域下,会被当做js代码执行。当表达式中js代码的逻辑过于复杂的时候,前面的处理方式是使用方法引用的方式,这里我们再介绍一种方式,用计算属性作为表达式的内容。
1.1 计算属性的定义
计算属性放在computed选项中,既然是属性,那就存在getter和setter方法,所以正常的定义方式如下:
上面定义了fullName这个计算属性,并定义了其getter和setter方法。在指令的表达式中直接调用计算属性,它会调用fullName的getter方法。当为fullName赋值时,vue会调用其setter方法。通常,setter方法很少用到,所以vue为我们提供了只有getter方法的计算属性的简写形式。
var vm = new Vue({
computed:{
fullName:function(){
return `${this.firstName} ${this.lastName}`;
}
}
});
简写方式是属性名后直接跟匿名函数,这个函数就是getter函数。也可以在属性名后接对象,在对象中定义getter函数,不定义setter函数,该方式不常用,所以这里不做代码演示。
1.2 计算属性与方法的区别
如上面的例子,如果我们也可以定义一个getFullName()方法,返回同样的字符格式,然后在指令的表达式中使用该方法,同样能够达到目的。这样看来,计算属性比起方法,其定义反而麻烦了许多。
其实不然,计算属性与方法的最大的区别在于,计算属性有缓存功能,使用方法时,每次都会计算并返回结果,而计算属性只有当其内部的依懒项发生变化时才会重新计算,返回并缓存结果,当内部依赖项没有发生变化时,属性会直接返回缓存结果,所以计算属性要比方法的效率稍高。这里的内部依懒项就是firstName和lastName两个数据项。
2 watch监听器
2.1 监视器的定义
Vue使用watch来监听数据的变化,这里的“数据”指代的范围比较广,它可以是data选项中的值,也可以是props选项的值,还可以是第三方插件的值(比如路由插件vue-route的中路由的变化)。
Vue使用watch选项来定义监听器,watch后接对象,这个对象的键是需要观察的数据或表达式,而其值是当该键发生变化后的处理逻辑,这个处理逻辑的形式包括以下几种:
- 函数形式,该函数也叫回调函数,当监听的键发生变化后,vue会调用该函数,回调函数有2个参数,分别是变化之后的值(新值)和变化之前的值(旧值)
- 方法名形式,在watch选项之外定义了一个处理方法,在watch中通过字符串的形式指定方法
- 对象形式,对象形式除了指定回调函数外,还可以使用其他选项,以这种形式定义监听器,功能是最全的。对象的键包括:
- handler键:指定回调函数
- deep键:bool值,表示是否深度监听,当deep为true时,如果watch监听的是一个对象,那么这个对象的任何属性发生变化时(不管这个属性嵌套了多少层),该handler回调函数都会被调用。
- immediate键:表示该监听是否立即被调用,正常情况,监听对象应先有一个值,当这个值发生变化后,在触发watch。但是,当设置immediate后,该对象在第一次赋值时,这个监听回调也会被触发。
- 数组形式,上面所说的,不管是函数形式,方法名形式还是对象形式,他们都只能定义一个回调函数,而数组形式,是将上面的形式封装到数组中,这样,当值发生变化后,可以有多个回调函数。
2.2 监视器实例
在使用vue-route插件做前端路由时,可以在面包屑组件中监听路由变化,改变面包屑的值。通过vue的插件功能将vue-route注入,注入后vue-route为我们提供了两个对象$router
和$route
,我们可以在任何组件内通过 this.$router
访问路由器,通过 this.$route
访问当前路由,后续章节会介绍route。
我们需要监听$route
对象,当路由发生变化后做响应的改变即可:
var vm = new Vue({
watch:{
'$route':function(to, from) {
// 对路由变化作出响应...
}
}
});
3 filters过滤器
过滤器常常用来做显示格式化,比如,我们从服务器上获取用户信息时,gender字段表示用户性别,0表示女,1表示男,2表示未知。如果直接将012的值显示在界面上,用户会不知这些数字代表的含义,这时,我们就可以使用过滤器来做显示格式化。
3.1 过滤器的定义
vue使用filters选项定义过滤器,filters选项后接对象,在对象中定义过滤器函数。在HTML模板中,在js表达式中使用管道符|
添加过滤器。注意,在定义过滤器函数时,该函数的第一个参数为管道符前的表达式的计算结果值。
{{gender | genderFilter}}
过滤器函数可以设置任意多参数,但第一个参数必须为管道前的表达式的计算结果,如下,我们定义了一个过滤器A,他有2个参数,在调用时,第一个参数是隐形传递的。
{{gender | genderFilter("foo")}}
过滤器后还可以接过滤器,这里不再深入。
3.2 过滤器实例
枚举过滤器
在实际开发中,我们可以使用枚举过滤器来简化过滤器的使用,这里我们定义一个bool类型的枚举,js中没有枚举,我们使用的数组来定义:
//enums.js
export const BoolEnum = [
{key:0,value:"否"},
{key:1,value:"是"},
]
定义过滤器函数
//filters.js
export const enumFilter function(value,enums){
for (let i = 0; i < enums.length; i++) {
let item = enums[i];
if (item.key == key) {
return item.value;
}
}
return "N/A";
}
在HTML模板中使用
是否启用:{{isActive | enumFilter(boolEnum)}}
格式化货币过滤器
前面我们将自定义指令时,介绍了通过指令的方式格式化数字,现在我们使用过滤器的方式来实现该功能:
//filters.js
export const moneyFilter function(value){
value = value + "";
let hasDot = /\./g;
let patt = /\B(?=(\d{3})+\.)/g
if (!hasDot.test(value)) {
//没有小数点的正则表达式
patt = /\B(?=(\d{3})+$)/g
}
return value.replace(patt, ",");
}
在HTML模板中使用
总价:{{total | moneyFilter}}