过滤器的概念
- 过滤器是输送介质管道上不可缺少的装置,就是把不必要的东西过滤掉
- 实质: 不改变原始数据,只对原数据进行处理,返回过滤后的数据
- 本质: 函数
- 用途: 常用于文本的格式化
- 用处: 插值表达式和
v-bind属性绑定
<!-- 插值表达式 -->
{{ message | capitalize }}
<!-- v-bind属性绑定 -->
<div v-bind:id="message | capitalize"></div>
注意:
- 过滤器函数一定要有return值
- 过滤器的第一个形参就是管道符 "|" 前面待处理的值
局部挂载
- 局部过滤器定义到filters节点下,只能在当前组件实例所控制的el区域内使用
<p>message的值是:{{ message | capi }}</p>
data(){
return { message:'hello filters' }
},
filters:{
capi(payload){
const first = payload.charAt(0).toUpperCase()
const other = payload.slice(1)
// 一定要有返回值
return first + other
}
}
全局挂载
-
在多个组件实例之间共享的过滤器,独立于每个组件实例之外
-
全局挂载需要使用
Vue.filter()方法- 参数①: 过滤器的名字
- 参数②: 过滤器的处理函数
/*
filter/index.js
定义全局过滤器
*/
export default function fix2Num(payload){
return Number( payload || 0 ).toFixed(2)
}
/*
main.js
挂载到Vue实例中
*/
import * as filters from '@/filters';
Object.keys(filters).forEach((key) => {
Vue.filter(key, filters[key]);
});
<!-- 在模板中使用 -->
<h1>message的值是:{{ num | fix2Num }}</h1>
注意:当全局过滤器和局部过滤器重名时,会采用局部过滤器
串联过滤器
- 过滤器可链式调用
- 即已经过滤完成的结果,继续传给下一个过滤器
<h1>num:{{ price | fixed2Num | toRMB }}</h1>
filters:{
fixed2Num(payload){
return Number(payload).toFixed(2)
},
toRMB(payload) {
return '¥' + payload
},
}
过滤器传参
- 过滤器本质是一个函数,可接受参数
- 函数第一个参数永远是原数据,后续是自定义参数
<h1>num:{{ price | fixed2Num('rmb',3) }}</h1>
- 剩余参数
rest写法
filters:{
fixed2Num(payload,...args){
return `${args[0]==='rmb'?'¥':'$'}${Number(payload).toFixed(args[1])}`
},
}
- 形参写法
filters:{
fixed2Num(payload,type = 'rmb',num = 2){
return `${type==='rmb'?'¥':'$'}${Number(payload).toFixed(num)}`
},
}
过滤器原理
- 在模板中,过滤器写法如下:
<!-- 普通使用 -->
<h1>num:{{ price | fixed2Num }}</h1>
<!-- 串联调用 -->
<h1>num:{{ price | fixed2Num | toRMB }}</h1>
<!-- 传参调用 -->
<h1>num:{{ price | fixed2Num('rmb',3) }}</h1>
- 经过模板编译之后,转变成以下形式
// 普通使用
_s(_f('fixed2Num')(price))
// 串联调用
_s(_f('toRMB')(_f('fixed2Num')(price)))
// 传参调用
_s(_f('fixed2Num')(price,'rmb',3))
_f()函数是什么?
- _f函数是
resolveFilter的别名
- 作用: 找到注册的
fixed2Num过滤器,并且返回出去
_s()函数是什么?
toString函数的别名
-
过滤器执行原理:
- 执行
fixed2Num过滤器函数并将price当参数传入 - 拿到参数后调用
toString函数 - 最终
toString函数的执行结果保存到VNode的text属性中渲染成视图
- 执行
resolveFilter函数
- 作用就是找到过滤器
- 通过
resolveAsset函数能找到就返回过滤器,找不到就返回identity
// resolveFilter函数
function resolveFilter (id) {
return resolveAsset(this.$options, 'filters', id, true) || identity
}
identity是什么?
- 函数,传入什么值就返回什么值
resolveAsset函数
- 作用是找到模板中写的过滤器
- 源码如下:
/*
options:当前组件实例
type:字符串`'filters'
id:过滤器函数名
*/
function resolveAsset (options, type, id, warnMissing) {
if (typeof id !== 'string') return
var assets = options[type];
if (hasOwn(assets, id)) { return assets[id] }
var camelizedId = camelize(id);
if (hasOwn(assets, camelizedId)) { return assets[camelizedId] }
var PascalCaseId = capitalize(camelizedId);
if (hasOwn(assets, PascalCaseId)) { return assets[PascalCaseId] }
var res = assets[id] || assets[camelizedId] || assets[PascalCaseId];
if (process.env.NODE_ENV !== 'production' && warnMissing && !res) {
warn(
'Failed to resolve ' + type.slice(0, -1) + ': ' + id,
options
);
}
return res
}
- 判断
id是否为字符串,如果不是则直接返回undefined,然后执行identitiy函数 - 声明变量
assets保存options['filters'],过滤器的集合 - 判断
assets是否含有id属性的值,有则直接返回assets[id](其实就是filters) - 若没有则通过
camelize函数将id驼峰化后再判断自身含有id属性 - 若还没有则通过
capitalize将id首字母大写,继续判断 - 最后返回三者其中之一
- 如果是生产环境,并且允许报警告,而且上述并无返回,则直接报警告没找到该过滤器函数
过滤器的解析
- 通过
parseFilters函数, 专门用来解析过滤器 - 在
Vue的 src/compiler/parser/filter-parser.js中
-
解析原理:
- parseFiltersh函数:拿到过滤器名字和参数,循环调用
wrapFilter函数 - 将过滤器名称和
字符串'filter',传入wrapFilter函数
// 核心代码 for (i = 0; i < filters.length; i++) { expression = wrapFilter(expression, filters[i]) }- wrapFilter:通过
indexOf()判断是否有参数,返回的拼接字符串
function wrapFilter (exp: string, filter: string): string { const i = filter.indexOf('(') if (i < 0) { // _f: resolveFilter return `_f("${filter}")(${exp})` } else { const name = filter.slice(0, i) const args = filter.slice(i + 1) return `_f("${name}")(${exp}${args !== ')' ? ',' + args : args}` } } - parseFiltersh函数:拿到过滤器名字和参数,循环调用
过滤器原理主要分为两个阶段:
- 编译: 编译阶段将带有过滤器的模板编译成函数调用
- 执行: 通过
_f()查询挂载的过滤器,执行过滤器函数