过滤器,本质上就是一个函数。其作用在于用户输入数据后,它能够进行处理,并返回一个数据结果。
Vue.js 与 AngularJS 中的过滤器语法有些相似,使用管道符(|)进行连接,代码示例如下:
1
|
{{'abc' | uppercase}} 'abc' => 'ABC'
|
这里使用了Vue.js 内置的过滤器 uppercase,将字符串中的字母全部转换成大写形式。
Vue.js 支持在任何出现表达式的地方添加过滤器,除了上面例子中的 双大括号 表达式之外,还可以在绑定指令的表达式后调用,代码示例如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
<
div
id
=
"app"
>
<
span
v-text
=
"message | uppercase"
></
span
>
</
div
>
<
script
src
=
"//cdn.bootcss.com/vue/1.0.26/vue.js"
></
script
>
<
script
>
new Vue({
el:'#app',
data:{
message:'hello world!'
}
})
</
script
>
|
渲染为: => HELLO WORLD!
Vue 2.x 中,过滤器只能在 mustache 绑定中使用。为了在指令绑定中实现同样的行为,你应该使用计算属性。
过滤器可以串联:
1
|
{{ message | filterA | filterB }}
|
这里可以看一个例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
<
div
id
=
"app"
>
<
h1
>{{'ABCDE' |lowercase | capitalize }}</
h1
>
</
div
>
<
script
src
=
"//cdn.bootcss.com/vue/1.0.26/vue.js"
></
script
>
<
script
>
new Vue({
el:'#app',
data:{
message:''
}
})
</
script
>
|
lowercase 过滤器:把数据变成小写形式
capitalize过滤器:把首字母变成大写形式
// 'ABCDE' -> 'abcde' -> 'Abcde'
过滤器可以接受参数,参数跟在过滤器名称后面,参数之间以空格分隔。代码示例如下:
1
|
{{ message | filterA('arg1', arg2) }}
|
过滤器函数将始终以表达式的值作为第一个参数,带引号的参数会被当作字符串处理,而不带引号的参数会被当作数据属性名来处理。
这里的 message 将作为第一个参数,字符串arg1 作为第二个参数,表达式 arg2 的值在计算出来以后作为第三个参数传给过滤器。同时,Vue.js 的过滤器支持链式调用,上一个过滤器的输出结果可以作为下一个过滤器的输入
内置过滤器
必须指出的是,在Vue2.0中,删除了所有的内置过滤器
1、字母操作
Vue.js 内置了 capitalize、uppercase、lowercase 三个过滤器用于处理英文字符。注意:这三个过滤器仅针对英文字符串使用
1-1、capitalize
capitalize 过滤器用于将表达式中的首字母转换为大写形式
1
|
{{'abc' | capitalize}} // 'abc' => 'Abc'
|
1-2、uppercase
uppercase 过滤器用于将表达式中的所有字母转换为大写形式
1
|
{{'abc' | uppercase}} // 'abc' => 'ABC'
|
1-3、lowercase
lowercase 过滤器用于将表达式中的所有字母转换为小写形式
1
|
{{'ABC' | lowercase}} // 'ABC' => 'abc'
|
2、限制
Vue.js 中内置了 limitBy、filterBy、orderBy 三个过滤器用于处理并返回过滤后的数组,比如与v-for搭配使用。
注意:这三个过滤器所处理的表达式的值必须是数组,否则程序会报错
2-1、limitBy
limitBy 过滤器的作用是限制数组为开始前的 N 个元素,其中,N 由传入的第一个参数指定,表示限制几个,默认为 0, 即取全部的元素。第二个参数可选,用于指定从哪开始,比如:第一个参数是4,第二个参数是5,则表示取4个元素,从下标为5的元素开始。代码示例如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
<
div
id
=
"app"
>
<
ul
>
<!--第二个参数不指定,即取全部,从0开始-->
<
li
v-for
=
"item in items | limitBy"
>`item`</
li
>
</
ul
>
</
div
>
<
script
src
=
"//cdn.bootcss.com/vue/1.0.26/vue.js"
></
script
>
<
script
>
new Vue({
el:'#app',
data:{
items:[1,2,3,4,5,6,7,8,9,10]
}
})
</
script
>
|
1
2
3
4
5
6
|
<
div
id
=
"app"
>
<
ul
>
<!--只显示5个元素,从0开始-->
<
li
v-for
=
"item in items | limitBy 5"
>`item`</
li
>
</
ul
>
</
div
>
|
1
2
3
4
5
6
|
<
div
id
=
"app"
>
<
ul
>
<!--显示4个,从下标为3的元素开始 注意:下标是从0开始-->
<
li
v-for
=
"item in items | limitBy 4 3"
>`item`</
li
>
</
ul
>
</
div
>
|
还可以这么使用:
1
2
3
4
5
6
|
<
div
id
=
"app"
>
<
ul
>
<!--取6个,从下标为4的元素开始 注意:数组的长度是arr.length -->
<
li
v-for
=
"item in items | limitBy items.length-4 4"
>`item`</
li
>
</
ul
>
</
div
>
|
2-2、filterBy
filterBy过滤器的使用比较灵活,其第一个参数可以是字符串或者函数,过滤条件是:'string || function' + in + 'optionKeyName'
如果第一个参数是字符串,那么将在每个数组元素中搜索它,并返回包含该字符串的元素组成的数组。代码示例如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
<
div
id
=
"app"
>
<
ul
>
<
li
v-for
=
"val in arr | filterBy 'a'"
>`val`</
li
>
</
ul
>
</
div
>
<
script
src
=
"//cdn.bootcss.com/vue/1.0.26/vue.js"
></
script
>
<
script
>
new Vue({
el:'#app',
data:{
arr:['pear','orange','cherry','lemon']
}
})
</
script
>
|
如果数组元素是一个对象,过滤器将递归地在它所有属性中搜索。为了缩小搜索范围,可以指定一个搜索字段。代码示例如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
<
div
id
=
"app"
>
<
input
v-model
=
"uname"
>
<
ul
>
<
li
v-for
=
"user in users | filterBy uname in 'uname'"
>`user`.`uname`</
li
>
</
ul
>
</
div
>
<
script
src
=
"//cdn.bootcss.com/vue/1.0.26/vue.js"
></
script
>
<
script
>
new Vue({
el:'#app',
data:{
uname:'',
users:[
{uname:'Tom'},
{uname:'Jerry'},
{uname:'Kobe'},
{uname:'James'}
]
}
})
</
script
>
|
如果 filterBy 的第一个参数是函数,则过滤器将根据函数的返回结果进行过滤。此时 filterBy过滤器将调用 Javascript 数组中内置的函数 filter() 对数组进行处理,待过滤数组中的每个元素都将作为参数输入并执行传入 filterBy 中的函数。
只有函数返回结果为 true的数组元素才符合条件并将存入一个新的数组,最终返回结果即为这个新的数组。
2-3、orderBy
orderBy 过滤器的作用是返回排序后的数组。过滤条件是:'string || array || function' + 'order>=0 为升序 || order<=0 为降序'.
第一个参数可以是字符串、数组或者函数,第二个参数order可选,决定结果为升序或降序排列,默认为1,即升序排列
若输入参数为字符串,则可同时传入多个字符串作为排序键名,字符串之间以空格分隔。代码示例如下:
1
2
3
4
5
|
<
ul
>
<
li
v-for
=
"user in users | orderBy 'lastName' 'firstName' 'age'"
>
`user`.`lastName` `user`.`firstName` `user`.`age`
</
li
>
</
ul
>
|
此时,将按照传入的排序键名的先后顺序进行排序。也可以将排序键名按照顺序放入一个数组中,然后传入一个数组参数给 orderBy 过滤器即可。代码示例如下:
1
2
3
4
5
6
|
<!--sortKey = ['lastName' 'firstName' 'age'];-->
<
ul
>
<
li
v-for
=
"user in users | orderBy sortKey"
>
`user`.`lastName` `user`.`firstName` `user`.`age`
</
li
>
</
ul
>
|
升序排列:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
<
div
id
=
"app"
>
<
input
type
=
"text"
v-model
=
"a"
>
<
ul
>
<
li
v-for
=
"val in arr | orderBy 1"
>
`val`
</
li
>
</
ul
>
</
div
>
<
script
src
=
"//cdn.bootcss.com/vue/1.0.26/vue.js"
></
script
>
<
script
>
new Vue({
el:'#app',
data:{
a:'',
arr:['pear','cherry','lemon','orange']
}
})
</
script
>
|
降序排列:
1
2
3
4
5
6
7
8
|
<
div
id
=
"app"
>
<
input
type
=
"text"
v-model
=
"a"
>
<
ul
>
<
li
v-for
=
"val in arr | orderBy -1"
>
`val`
</
li
>
</
ul
>
</
div
>
|
3、json 过滤器
Vue.js 中的 json 过滤器本质上是 JSON.stringify() 的精简缩略版,可将表达式的值转换为 JSON 字符串,即输出表达式经过 JSON.stringify() 处理后的结果。
json 可接受一个类型为 Number 的参数,用于决定转换后的 JSON 字符串的缩进距离,如果不输入该参数,则默认为2。
不输入参数,默认为2的示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
<
div
id
=
"app"
>
<
p
>{{information | json}}</
p
>
</
div
>
<
script
src
=
"//cdn.bootcss.com/vue/1.0.26/vue.js"
></
script
>
<
script
>
new Vue({
el:'#app',
data:{
information:{'name':'Roger', 'age':26}
}
})
</
script
>
|
为了看到效果,我们输入一个参数20:
1
2
3
|
<
div
id
=
"app"
>
<
p
>{{information | json 20}}</
p
>
<!-- 以20个空格的缩进打印一个对象 -->
</
div
>
|
4、currency 过滤器
currency 过滤器的作用是将数字值转换为货币形式输出。
第一个参数接受类型为 String 的货币符号,如果不输入,则默认为美元符号$。
第二个参数接受类型为 Number的小数位,如果不输入,则默认为2.
注意:如果第一个参数采取默认形式,而需要第二个参数修改小数位,则第一个参数不可省略
不输入参数,默认形式
1
2
3
4
5
6
7
8
9
10
11
12
13
|
<
div
id
=
"app"
>
<
h1
>{{amount | currency}}</
h1
>
</
div
>
<
script
src
=
"//cdn.bootcss.com/vue/1.0.26/vue.js"
></
script
>
<
script
>
new Vue({
el:'#app',
data:{
amount: '12345'
}
})
</
script
>
|
使用其它货币符号:
1
2
3
|
<
div
id
=
"app"
>
<
h1
>{{amount | currency '¥'}}</
h1
>
</
div
>
|
将小数调整为3位:
1
2
3
|
<
div
id
=
"app"
>
<
h1
>{{amount | currency '¥' 3}}</
h1
>
</
div
>
|
5、debounce 过滤器
debounce 过滤器的作用是延迟处理一定的时间执行。其接受的表达式的值必须是函数,因此,一般与 v-on 等指令结合使用。
debounce 接受一个可选的参数作为延迟时间,单位为毫秒。如果没有该参数,则默认的延迟时间为300ms,经过 debounce 包装的处理器在调用之后将至少延迟设定的时间再执行。 如果在延迟结束前再次调用,则延迟时长将重置为设定的时间。
通常,在监听用户 input 事件时使用 debounce 过滤器比较有用,可以防止频繁调用方法。debounce 的用法参考如下:
1
|
<
input
@
keyup
=
"onKeyup | debounce 500"
>
|
自定义过滤器
1、filter语法
在Vue.js 中也存在一个全局函数 Vue.filter 用于构造过滤器:
Vue.filter(filterName, function(input){...})
该函数接受两个参数,第一个参数为自定义的过滤器名称,第二个参数则是具体的过滤器函数,过滤器函数以值为参数,返回转换后的值
2、单个参数
注册一个名为 reverse 的过滤器,作用是将字符串反转输出。代码示例如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
<
div
id
=
"app"
>
<
input
v-model
=
"message"
>
<
span
v-text
=
"message | reverse"
>`message`</
span
>
</
div
>
<
script
src
=
"//cdn.bootcss.com/vue/1.0.26/vue.js"
></
script
>
<
script
>
Vue.filter('reverse',function(message){
return message.split('').reverse().join('');
});
new Vue({
el:'#app',
data:{
message:''
}
})
</
script
>
|
注册一个名为 double 的过滤器,作用是将数字补全成两位数输出。代码示例如下
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
<
div
id
=
"app"
>
<
input
v-model
=
"value"
>
<
p
v-text
=
"value | double"
>`value`</
p
>
</
div
>
<
script
src
=
"//cdn.bootcss.com/vue/1.0.26/vue.js"
></
script
>
<
script
>
Vue.filter('double',function(value){
return value<
10
? '0'+value : value
});
new Vue({
el:'#app',
data:{
value:''
}
})
</script>
|
注册一个名为 date 的过滤器,作用是将当前时间毫秒数以年月日时分秒的格式输出。代码示例如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
<
div
id
=
"app"
>
<
p
v-text
=
"message | date"
>`message`</
p
>
</
div
>
<
script
src
=
"//cdn.bootcss.com/vue/1.0.26/vue.js"
></
script
>
<
script
>
Vue.filter('date',function(message){
var now = new Date(message);
return now.getFullYear()+'-'
+(now.getMonth()+1)+'-'
+now.getDate()+' '
+(now.getHours()<
12
?'0'+now.getHours():now.getHours())+':'
+(now.getMinutes()<10?'0'+now.getMinutes():now.getMinutes())+':'
+now.getSeconds();
});
new Vue({
el:'#app',
data:{
message:Date.now()
}
})
</script>
|
3、多个参数
过滤器函数除了以值作为参数外,也可以接受任意数量的参数,参数之间以空格分隔。代码示例如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
<
div
id
=
"app"
>
<
input
v-model
=
"message"
>
<
p
v-text
=
"message | wrap 'before' 'end'"
>`message`</
p
>
</
div
>
<
script
src
=
"//cdn.bootcss.com/vue/1.0.26/vue.js"
></
script
>
<
script
>
Vue.filter('wrap',function(value, begin, end){
return begin +' '+ value + ' '+ end
});
new Vue({
el:'#app',
data:{
message:''
}
})
</
script
>
|
4、双向过滤器
上面的过滤器都是在 Model 数据输出到 View 层之前进行数据转化的,实际上 Vue.js 还支持把来自视图(input元素)的值在写回模型前进行转化,即双向过滤器
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
Vue.filter(
'filterName'
,{
//model ---> view
//read 函数可选
read:
function
(val){
...
},
//view ---> model
//write 函数将在数据被写入Model 之前调用
//两个参数分别为表达式的新值和旧值
write:
function
(newVal, oldVal){
...
}
})
|
代码示例如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
<
div
id
=
"app"
>
<
p
>`message`</
p
>
<
input
type
=
"text"
v-model
=
"message | twoWayFilter"
>
</
div
>
<
script
src
=
"//cdn.bootcss.com/vue/1.0.26/vue.js"
></
script
>
<
script
>
Vue.filter('twoWayFilter',{
read:function(val){
return 'read'+' '+val;
},
write:function(newVal, oldVal){
return oldVal+' '+ 'write';
}
});
new Vue({
el:'#app',
data:{
message:'hello world'
}
})
</
script
>
|
在初始情况下,message 表达式的值经过 twoWayFilter 中的 read 函数处理,输出到 view 层
当我们在 input 框中修改 message 的值时,twoWayFilter 中的 write 函数将在数据输出到 Model 层之前处理,这里将返回 message 的旧值 + 'write',然后输出到 Model层,因此 message的值变更为'hello world write' 并显示到页面上
常见问题解析
1、filterBy/orderBy 过滤后 $index 的索引
在使用 filterBy 或者 orderBy 对表达式进行过滤时,如果同时需要将 $index 作为参数,此时的 $index将会根据表达式数组或对象过滤后的值进行索引
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
<
ul
id
=
"app"
>
<
li
v-for
=
"item in items | orderBy 'age'"
>
`item`.`name` - {{$index}}
</
li
>
</
ul
>
<
script
src
=
"//cdn.bootcss.com/vue/1.0.26/vue.js"
></
script
>
<
script
>
new Vue({
el:'#app',
data:{
items:[
{name:'Roger', age:26},
{name:'Sarahling', age:27},
{name:'Daisy', age:1}
]
}
})
</
script
>
|
2、自定义filter 的书写位置
自定义 filter 可以写在全局 Vue下,例如:
1
2
3
|
Vue.filter(
'reverse'
,
function
(message){
return
message.split(
''
).reverse().join(
''
);
});
|
也可以写在Vue 实例当中,例如:
1
2
3
4
5
6
7
8
9
10
11
12
|
var
vm =
new
Vue({
el:
'#example'
,
data:{
},
filters:{
//自定义 filter 事件的位置
reverse:
function
(value){
return
value.split(
''
).reverse().join(
''
);
}
}
})
|
二者本质上并无区别,可任选一种使用。但是,采用Vue.filter 在全局定义时,需要在实例化 Vue 之前定义,否则自定义的 filter 不起作用