过滤器的实现原理

首先介绍一下过滤器的使用,过滤器是来用格式化文本的,它可以用在两个地方:双花括号和v-bind表达式。:

<!-- 双花括号 --!>
{{ message | capitalize}}

<!-- 在v-bind中--!>
<div v-bind:id = 'rawId | formatId'></div>

然后我们在一个组件的选项中定义本地的过滤器:

    filters: {
        capitalize: function(value) {
            if(!value) return ''
            value = value.toString()
            return value.charAt(0).toUpperCase() + value.slice(1)
        }
    }

或者在创建vuejs实例之前定义全局过滤器:

    Vue.filter('capitalize', function(value) {
        if(!value) return ''
        value = value.toString()
        return value.charAt(0).toUpperCase() + value.slice(1)
    })

    new Vue({
    ...
    })

过滤器会将表达式的值作为第一个参数,比如message的值作为第一个参数。
此外,过滤器可以连写,{{ message | filterA | filterB }}。然后message的值先被filterA执行回调,回调的值再进入filterB执行回调。并且因为过滤器是函数,所以也能接收参数:{{ message | filterA('arg1', arg2)}},这里filterA被定义为接收三个参数的过滤器函数,其中message作为第一个函数,arg1作为第二个,arg2作为第三个参数。

过滤器原理

过滤器原理并不复杂,用之前的例子举例:

{{ message | capitalize }}

这个过滤器再模板编译阶段会编译成下面的样子:

_s(_f('capitalize ')(message))

其中_f函数是resolveFilter的别名,其作用是从this.\(options.filters中找出注册的过滤器并返回。因此,上面例子中的_f('capitalize')与this.\)options.filters['capitalize ']相同。而this.$options.filters['capitalize ']就是我们注册的capitalize 过滤器函数,因此,_f('capitalize ')(message)其实就算执行了过滤器capitalize 并传递了参数message。
_s函数是toString函数的别名,toString函数的代码如下:

function toString(val) {
  return val == null
  ? ''
  : typeof val === 'object'
    ? JSON.stringify(val, null, 2)
    : String(val)
}

所以整个过程就是,先将message传入capitalize 运行,然后将处理后的结果传递给toString函数,并最终保存到VNode中的text属性中,然后返回结果直接被拿去渲染视图。

串联过滤器

连续使用过滤器:

{{ message | capitalize | suffix }}

本地定义的过滤器如下:

filters: {
  capitalize: function(value) {
   if(!value) return ''
   value = value.toString()
   return value.charAt(0).toUpperCase() + value.slice(0) 
  },
  suffix: function(value, symbol = '~') {
    if(!value) return ''
    return value + symbol
  }
}

最后在模板编译阶段回编译成下面的样子:

_s(_f("suffix")(_f("capitalize")(message)))

从代码中可以看出只是一层一层的递归而已,先将message传入capitalize函数,然后将结果传入suffix函数,最后传入到toString中,之后渲染到界面。

过滤器接收参数

前面说过滤器可以接收参数,例如:

{{ message | capitalize | suffix('!) }}

设置了参数的过滤器最终被编译成这样:

_s(_f("suffix")(_f("capitalize")(message), '!'))

可以看到,两者唯一的区别就是,当模板编译之后,会将在模板中给过滤器设置的参数添加在过滤器函数的参数中。注意:这里是从第二个参数开始,第一个参数永远都是之前操作链的结果。

posted @ 2021-10-14 17:21  卿六  阅读(382)  评论(0编辑  收藏  举报