过滤器是什么?
过滤器是一种在模板中处理数据的便捷方式, 会经常在其他模板语言中见到, 他们特别适合对字符串和数字进行简单的显示变化.
1. 通过案例理解过滤器
示例: 对于数字价格处理
1.1 Mastache语法中处理价格数字
<div id="app">
<!-- 正常处理 -->
<p>苹果价格:{{ (priceOne/100).toFixed(2) }} 元/斤</p>
<p>梨子价格:{{ (priceTwo/100).toFixed(2) }} 元/斤</p>
<p>香蕉价格:{{ (priceThree/100).toFixed(2) }} 元/斤</p>
</div>
<script>
const vm = new Vue({
el: "#app",
data: {
priceOne: 2312,
priceTwo: 1825,
priceThree: 1634,
}
})
</script>
我们就会发现一件事情, 同样的逻辑我们要处理三次,这种处理方案,页面需要使用到多少次价格,我们就需要处理多少次相同的逻辑
我们在回顾到目前为止我们所学的知识, 有什么方方案可以很好的将逻辑抽离出来吗, 计算属性和侦听器显然不合适,因为都需要检测依赖数据的变化, 有多少数据就需要多少的计算属性,和多少的侦听器, 反而不美
想来想去,定义一个方法通过接受不同的参数来处理我们的相同的逻辑,每次只要调用这个方法就可以了,挺不错的, 尝试一下
1.2 方法处理相同逻辑
<div id="app">
<!-- 使用方法处理价格 -->
<p>苹果价格:{{ priceHandle(priceOne)}} 元/斤</p>
<p>梨子价格:{{ priceHandle(priceTwo)}} 元/斤</p>
<p>香蕉价格:{{ priceHandle(priceThree)}} 元/斤</p>
</div>
<script>
const vm = new Vue({
el: "#app",
data: {
priceOne: 2312,
priceTwo: 1825,
priceThree: 1634,
},
methods:{
priceHandle(price){
return (price/100).toFixed(2)
}
}
})
</script>
方法也有不美之处,就是寓意化不够明确,所有的事情都需要定义方法来处理, 那么方法的耦合性就会很高
所以对于数据的先期处理, vue给我们提供了过滤器 filters
1.3 使用filters 过滤器处理数据
注意过滤器的方法定义在filters属性中
<div id="app">
<!-- 过滤器 filter -->
<p>苹果价格:{{ priceOne | formatPrice}} 元/斤</p>
<p>梨子价格:{{ priceTwo | formatPrice }} 元/斤</p>
<p>香蕉价格:{{ priceThree | formatPrice }} 元/斤</p>
</div>
<script>
const vm = new Vue({
el: "#app",
data: {
priceOne: 2312,
priceTwo: 1825,
priceThree: 1634,
},
filters:{
formatPrice(price){
return (price/100).toFixed(2)
}
}
})
</script>
其实这个时候,我们甚至连后面的元/斤
都可以处理到过滤器中
<div id="app">
<!-- 过滤器 filter -->
<p>苹果价格:{{ priceOne | formatPrice}} </p>
<p>梨子价格:{{ priceTwo | formatPrice }} </p>
<p>香蕉价格:{{ priceThree | formatPrice }} </p>
</div>
<script>
const vm = new Vue({
el: "#app",
data: {
priceOne: 2312,
priceTwo: 1825,
priceThree: 1634,
},
filters:{
formatPrice(price){
return "¥"+(price/100).toFixed(2) +'元/斤'
}
}
})
</script>
这样的好处很多, 代码重复更少, 可读性更强, 同时呢,维护性也更好, 如果要更改逻辑,只需要修改一次,而不是每个使用的地方都修改
2. 过滤器传参
通过案例,我们也了解了, 过滤器在使用时会将|
前面的内容作为过滤器函数的第一个参数,如果过滤器只需要这一个参数时, 过滤器本身不需要加括号
如果过滤器需要其他参数来动态改变逻辑怎么办,
这个时候过滤器在使用的时候就可以加括号执行,并传入相应的参数,输入的参数会作为第二个参数传递给过滤器
例如:
<div id="app">
<!-- 过滤器传参 -->
<p>苹果价格:{{ priceOne | formatPrice("¥")}} </p>
<p>梨子价格:{{ priceTwo | formatPrice("$") }} </p>
<p>香蕉价格:{{ priceThree | formatPrice("$") }} </p>
</div>
<script>
const vm = new Vue({
el: "#app",
data: {
priceOne: 2312,
priceTwo: 1825,
priceThree: 1634,
},
filters:{
formatPrice(price,symbol){
return symbol+(price/100).toFixed(2) +'元/斤'
}
}
})
</script>
这样我们就可以通过传参的方式来动态的改变过滤逻辑
3. 链式调用过滤器
过滤器还可以通过链式调用的方式在一个表达式中使用多个过滤器.
比如我们给刚才的案例添加一个四舍五入到整数的过滤器
<div id="app">
<!-- 链式调用过滤器 -->
<p>
苹果价格:{{ priceOne | roundPrice | formatPrice("¥")}}
</p>
<p>
梨子价格:{{ priceTwo | roundPrice | formatPrice("$") }}
</p>
<p>
香蕉价格:{{ priceThree | roundPrice | formatPrice("$") }}
</p>
</div>
<script>
const vm = new Vue({
el: "#app",
data: {
priceOne: 2312,
priceTwo: 1825,
priceThree: 1634,
},
filters:{
roundPrice(price){
return Math.round(price/100);
},
formatPrice(price,symbol){
return symbol+price.toFixed(2) +'元/斤'
}
}
})
</script>
这里首先会调用roundPrice 过来器, 会将价格传入到这个过滤器中处理, 然后在将处理后的结果传给第二个过滤器处理,最后输出到页面上
4. 属性使用过滤器
除了在插值,还可以在v-bind中使用过滤器,因为使用了v-bind动态绑定的属性,属性值已经不再是一个字符串,而是一个表达式了
<div id="app">
<!-- 动态绑定的属性使用过滤器 -->
<input type="text" :value="priceOne | roundPrice | formatPrice('¥')">
</div>
<script>
const vm = new Vue({
el: "#app",
data: {
priceOne: 2312,
priceTwo: 1825,
priceThree: 1634,
},
filters:{
roundPrice(price){
return Math.round(price/100);
},
formatPrice(price,symbol){
return symbol+price.toFixed(2) +'元/斤'
}
}
})
</script>
5. 还可以通过Vue构造函数注册全局过滤器
也就是说现在的过滤器是一个组件级的过滤器
如果我重新new 一个Vue实例, 这个过滤器将不能再另一个实例上使用
例如
<div id="app">
<p>苹果价格:{{ priceOne | roundPrice | formatPrice("¥")}} </p>
<p>梨子价格:{{ priceTwo | roundPrice | formatPrice("$") }} </p>
<p>香蕉价格:{{ priceThree | roundPrice | formatPrice("$") }} </p>
</div>
<div id="example">
<!-- 在第二个vue实例上不能使用第一个实例的过滤器, -->
{{ price | roundPrice }}
</div>
<script>
const vm = new Vue({
el: "#app",
data: {
priceOne: 2312,
priceTwo: 1825,
priceThree: 1634,
},
filters:{
roundPrice(price){
return Math.round(price/100);
},
formatPrice(price,symbol){
return symbol+price.toFixed(2) +'元/斤'
}
}
})
const vm2 = new Vue({
el:"#example",
data:{
price:6123
}
})
</script>
如果我们在第二个vue实例上使用过滤器就会报错,
所以我们可以注册全局过滤器,所有的组件都能使用
<div id="app">
<p>
苹果价格:{{ priceOne | roundPrice | formatPrice("¥")}}
</p>
<p>
梨子价格:{{ priceTwo | roundPrice | formatPrice("$") }}
</p>
<p>
香蕉价格:{{ priceThree | roundPrice | formatPrice("$") }}
</p>
</div>
<div id="example">
{{ price | formatPrice("$") }}
</div>
<script>
// 注册全局过滤器
Vue.filter("formatPrice",function(price,symbol){
return symbol+price.toFixed(2) +'元/斤'
})
const vm = new Vue({
el: "#app",
data: {
priceOne: 2312,
priceTwo: 1825,
priceThree: 1634,
},
filters:{
roundPrice(price){
return Math.round(price/100);
}
}
})
const vm2 = new Vue({
el:"#example",
data:{
price:6123
}
})
</script>
注册的全局过滤器,就可以在vue任何地方都可以使用
这种方式适合整个应用都会用到的过滤器,
6. 过滤器注意事项
6.1 过滤器中的this
过滤器是唯一不能使用this来访问数据或者其他方法的地方,这一点是故意设计成这样的, 因为过滤器应该是一个纯函数, 也就是对于同样的输入每次都返回同样的输出,而不涉及任何外部数据, 如果想访问外部数据可以通过参数传递.
6.2 过滤器使用的地方
另一件注意事项就是过滤器只能在插值和v-bind指令中使用过滤器,但是在Vue1 中,可以在任何可以使用表达式的地方使用过滤器