vue.js 过滤器使用及原理分享讨论

Vue.js 过滤器使用及原理分享讨论
一. 过滤器使用场景/语法/分类
  1. 使用场景

    在做页面的渲染时,过滤器主要帮助我们在不更改原数据的前提下,格式化文本。

    例子:

    // 页面在做数据渲染时,后台返回的数据格式为枚举类型,如:'01'-通过,'02'-不通过
    // 这时可使用过滤器来达到文本格式化的目的
    // html
    <el-table>
        <el-table-column label='是否通过' width='120'>
            <template slot-scope='{row}'>
                {{row.isAgree | filterFormat}}  // 注:row.isAgree将作为参数传递给filterFormat
            </template>
        </el-table-column>
    </el-table>
    // js
    export default{
       data(){
           return {
              agreeTp:{
                  '01':'通过',
                  '02':'不通过'
              }
           }
       },
       filters:{
             // 定义过滤器
             filterFormat:function(val){
                  if(!val)return "--";// 如果该属性没值,则在页面显示'--'
                  return this.agreeTp[val]
             }
       }
    }
    
  2. 使用语法

    2.1 在双花括号中

    {{ message | filterFormat }}
    

    2.2 在 v-bind

    <div :v-bind=' message | filterFormat '></div>
    
  3. 过滤器的分类

    3.1 全局过滤器

    Vue.filter('filterFormat', function (value){
        if (!value) return '--'
        return parseInt(value)  
    })
    

    注意:全局过滤器的定义需要放在Vue.js实例创建之前

    3.2 局部过滤器

    // 在一个组件的选项中定义本地过滤器
    filters:{
        filterFormat: function (value) {
            if (!value) return '--'
            return parseInt(value) 
        }
    }
    
二. 过滤器内部运作原理

原理部分的内容主要围绕模板过滤器语法是如何在模板编译阶段被编译成过滤器函数来展开

还记得在第一节中我们在DOM中使用过滤器的两种语法:

{{ message | filterFormat }}
// 或者是
<div :v-bind=' message | filterFormat '></div>

在模板编译阶段过滤器表达式将会被编译为过滤器函数

// 像这个样子的
_s(_f('filterFormat')(message))
  1. _f 函数是什么?
    1.1 _f 函数全名是:resolveFilter,这个函数的作用是从this.$options.filters中找出注册的过滤器并返回

    _f('filterFormat')(message)
    //  等价于
    this.$options.filters['filterFormat'](message) // message为参数
    // 很明显 this.$options.filters 返回一个对象
    

    1.2 resolveFilter又是如何找到过滤器的呢?

    让我们先看看resolveFilter函数的代码

    import { indentity,resolveAsset } from 'core/util/index' 
    
    export function resolveFilter(id){
        return resolveAsset(this.$options,'filters',id,true) || identity
    }
    

    resolveFilter的实现比较简单,内部直接调用resolveAsset,将option对象,类型,过滤器id,以及一个触发警告的标志作为参数传递,如果找到,则返回过滤器;找不到,则返回identity(这里先不讨论identity函数)。

    所以下一个问号就是resoveAsset?

    1.3 resolveAsset如何找到过滤器?

    代码如下:

    export function resolveAsset(options,type,id,warnMissing){ // 因为我们找的是过滤器,所以在 resolveFilter函数中调用时 type 的值直接给的 'filters',实际这个函数还可以拿到其他很多东西
        if(typeof id !== 'string'){ // 判断传递的过滤器id 是不是字符串,不是则直接返回
            return 
        }
        const assets = options[type]  // 将我们注册的所有过滤器保存在变量中
        // 接下来的逻辑便是判断id是否在assets中存在,即进行匹配
        if(hasOwn(assets,id)) return assets[id] // 如找到,直接返回过滤器
        // 没有找到,代码继续执行
        const camelizedId  = camelize(id) // 万一你是驼峰的呢
        if(hasOwn(assets,camelizedId)) return assets[camelizedId]
        // 没找到,继续执行
        const PascalCaseId = capitalize(camelizedId) // 万一你是首字母大写的驼峰呢
        if(hasOwn(assets,PascalCaseId)) return assets[PascalCaseId]
        // 如果还是没找到,则检查原型链(即访问属性)
        const result = assets[id] || assets[camelizedId] || assets[PascalCaseId]
        // 如果依然没找到,则在非生产环境的控制台打印警告
        if(process.env.NODE_ENV !== 'production' && warnMissing && !result){
            warn('Failed to resolve ' + type.slice(0,-1) + ': ' + id, options)
        }
        // 无论是否找到,都返回查找结果
        return result
    }
    
  2. _s 函数是什么?
    2.1 _s 函数的全称是 toString,过滤器处理后的结果会当作参数传递给 toString函数,最终 toString函数执行后的结果会保存到Vnode中的text属性中,渲染到视图中。
    2.2 _s 函数代码

    function toString(value){
        return value == null
        ? ''
        : typeof value === 'object'
          ? JSON.stringify(value,null,2)// JSON.stringify()第三个参数可用来控制字符串里面的间距
          : String(value)
    }
    

    即先对参数进行判断,没有则直接返回空字符,如果为对象类型则调用JSON.stringity(),非对象类型则调用String()方法

    在执行过滤器后一定要调用_s函数的原因是动态参数的预期值是一个字符串

让我们回到最初的问题:

模板过滤器表达式是如何被编译成过滤器函数的?

Vue.js中提供了一个parseFilters函数,专门用来解析过滤器,即在模板编译阶段使用该函数阶段将模板过滤器解析为过滤器函数调用表达式。

parseFilters的代码实现:

function parseFilters (filter) {
    let filters = filter.split('|')
    let expression = filters.shift().trim() // shift()删除数组第一个元素并将其返回,该方法会更改原数组
    let i
    if (filters) {
        for(i = 0;i < filters.length;i++){
            experssion = warpFilter(expression,filters[i].trim()) // 这里传进去的expression实际上是管道符号前面的字符串,即过滤器的第一个参数
        }
    }
    return expression
}
// warpFilter函数实现
function warpFilter(exp,filter){
    // 首先判断过滤器是否有其他参数
    const i = filter.indexof('(')
    if(i<0){ // 不含其他参数,直接进行过滤器表达式字符串的拼接
        return `_f("${filter}")(${exp})`
    }else{
        const name = filter.slice(0,i) // 过滤器名称
        const args = filter.slice(i+1) // 参数,但还多了 ‘)’
        return `_f('${name}')(${exp},${args}` // 注意这一步少给了一个 ')'
    }
}
结语

过滤器的作用是完成数据的格式化

实现原理:在编译阶段将过滤器编译成函数调用(串联过滤器则是一个嵌套的函数调用,前一个过滤器执行的结果是后一个过滤器函数的参数)。编译后通过调用resolveFilter函数找到对应过滤器并返回,其执行结果作为参数传递给toString函数,而toString执行后,其结果会保存在Vnode的text属性中,渲染到视图。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Vue.js过滤器是一种用于对数据进行处理和格式化的功能。在Vue.js中,有两种使用过滤器的方式:全局过滤器和局部过滤器。 全局过滤器可以在Vue实例创建之前定义,并在整个应用程序中使用。例如,在Vue实例创建之前,可以使用Vue.filter()方法定义一个全局过滤器。然后,在模板中使用管道符(|)将数据传递给过滤器进行处理。\[1\]例如,可以定义一个名为addPriceIcon的全局过滤器,用于在价格前添加货币符号: ``` Vue.filter("addPriceIcon", (value) => { return '¥' + value; }) ``` 然后,在模板中使用过滤器: ``` <p>电脑价格:{{price | addPriceIcon}}</p> ``` 局部过滤器只在特定的Vue实例中可用。可以在Vue实例的filters选项中定义局部过滤器。\[2\]例如,可以在Vue实例的filters选项中定义一个名为addPriceIcon的过滤器: ``` filters: { addPriceIcon(value) { return '¥' + value; } } ``` 然后,在模板中使用过滤器: ``` <p>电脑价格:{{price | addPriceIcon}}</p> ``` 无论是全局过滤器还是局部过滤器,都可以在模板中使用管道符(|)将数据传递给过滤器进行处理。过滤器可以接受参数,并在处理数据时使用这些参数。\[3\]例如,可以定义一个名为sum的全局过滤器,用于将传入的值加上4: ``` Vue.filter("sum", function(value) { return value + 4; }); ``` 然后,在模板中使用过滤器: ``` <p>{{message | sum}}</p> ``` 总结起来,Vue.js过滤器是一种用于对数据进行处理和格式化的功能。可以通过全局过滤器或局部过滤器来定义和使用过滤器。无论是全局过滤器还是局部过滤器,都可以在模板中使用管道符(|)将数据传递给过滤器进行处理。过滤器可以接受参数,并在处理数据时使用这些参数。 #### 引用[.reference_title] - *1* *2* [Vue.js过滤器filters](https://blog.csdn.net/m0_61961937/article/details/130302483)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^koosearch_v1,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [Vue.js基础-过滤器(filters)](https://blog.csdn.net/Jasmines1993/article/details/79665079)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^koosearch_v1,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值