• 面试题三:请你谈一谈Vue中的filter功能的实现


    Vue中过滤器(filter)的使用

    我们想一下有methods为什么要有filter的存在呢,因为filter的实现效率比methods要高的多。

    看一下官方定义:

    Vue.js 允许你自定义过滤器,可被用于一些常见的文本格式化。过滤器可以用在两个地方:双花括号插值和 v-bind 表达式 (后者从 2.1.0+ 开始支持)。过滤器应该被添加在 JavaScript 表达式的尾部,由“管道”符号指示:

    1. 局部过滤器(使用最频繁)

    语法

    • template
    1. {{ name | judgeRole }}
    2. //或者
    3. <div v-bind:id="rawId | formatId">div>

    上面的过滤器经过一顿操作之后就会变成:_s(_f("capitalize")(message))。

    _f:该函数其实就是resolveFilter的别名,作用是从_this.$options.filter找到过滤器并返回
    _s:该函数就是toString函数的别名,作用是拿到过滤之后的结果并传递给toString()函数,结果会保存到VNode中的text属性,返回结果直接渲染视图
     

    _f函数的原理 

    _f函数其实就是寻找过滤器的,如果找到过滤器就返回过滤器,找不到就返回与参数相同的值。它的代码其实很简单:

    1. import {identity, resolveAssets} from 'core/util/index'
    2. export function resolveFilter(id){
    3. return resolveAssets(this.$options, 'filters', id, true) || identity
    4. }

    我们重点来看一下resolveAssets到底做了什么事情。

    1. export function resolveAsset (options, type, id, warnMissing){
    2. if(typeof(id) !== 'string'){
    3. return
    4. }
    5. const assets = options[type]
    6. if(hasOwn(assets, id)) return assets[id]
    7. const camelizedId = camelize(id)
    8. if(hasOwn(assets, camelizedId)) return assets[camelizedId]
    9. const PascalCaseId = capitlize(camelizedId)
    10. if(hasOwn(assets, PascalCaseId)) return assets[PascalCaseId]
    11. //检查原型链
    12. const res assets[id] || assets[camelizedId] || PascalCaseId
    13. if(process.env.NODE_ENV!=='production'&& warnMissing&&!res){
    14. warn('Fail to resolve' + type.slice(0,-1)+':'+id, options)
    15. }
    16. return res
    17. }

    其实它的寻找过程也很简单,主要是做了以下的操作(id是过滤器id):

    1.判断过滤器id是否为字符串,不是则终止
    2.用assets存储过滤器
    3.hasOwn函数检查assets自身是否存在id属性,存在则返回
    4.hasOwn函数检查assets自身是否存在驼峰化后的id属性,存在则返回
    5.hasOwn函数检查assets自身是否存在将首字母大写后的id属性,存在则返回
    6.如果还是没有,就是去原型链找,找不到就会打印警告

    过滤器解析原理

    我们想一下,解析器是怎么解析过滤器的语法?其实在vue内部专门有这么一个函数用来解析过滤器语法:parseFilters

    它的原理就是解析过滤器列表,然后循环过滤器列表拼接字符串

    • script
    1. filter:{
    2. judgeRole(val) {
    3. if (val === '0') {
    4. return '平台'
    5. } else if (val === '1') {
    6. return '企业'
    7. } else if (val === '2') {
    8. return '企业用户'
    9. } else {
    10. return ''
    11. }
    12. }
    13. }

    说明

    • 过滤器函数中的value,就是 |前面的值,它相当于第一个参数
    • 在过滤器函数中一定要返回一个值,他就是我们对格式处理后的结果
    • 通俗的来讲,当为一个数据绑定一个过滤器后,每一次渲染这个数据的时候,他都会调用相应过滤器的函数

    实战

    使用vue-cli下载一个默认的项目,我使用vue/cli4默认的目录如下 

    1.在components文件夹下新建FilterLoc.vue表示局部的过滤器,并写上如下代码,我们的目的是把sunwukong首字母变成大写

    1. <script>
    2. export default {
    3. data(){
    4. return {
    5. name:'sunwukong'
    6. }
    7. },
    8. filters:{
    9. //当value改变的时候,他会执行这个函数
    10. capitalize:function (value) {
    11. //一定要返回一个值才能在组件中正常显示
    12. if (!value) return ''
    13. value = value.toString()
    14. return value.charAt(0).toUpperCase() + value.slice(1)
    15. }
    16. }
    17. }
    18. script>

    2.我们在App.vue中引入并映射成组件

    1. <script>
    2. import FilterLoc from '@/components/FilterLoc'
    3. export default {
    4. components:{
    5. FilterLoc
    6. }
    7. }
    8. script>

    3.运行项目,观察效果,我们发下sunwukong首字母已经大写

    2. 全局过滤器

    1.我们可以在入口文件定义全局过滤器,当然也可以是其他文件,这里我们把最后一个首字母变成大写

    • main.js
    1. /* 定义全局过滤器 */
    2. Vue.filter('capitalize', function (value) {
    3. if (!value) return ''
    4. const length = value.length - 1
    5. value = value.toString()
    6. return value.slice(0,length) + value.charAt(length).toUpperCase()
    7. })

    2.在components文件夹下新建FilterGlo.vue表示使用全局过滤器,并写上如下代码,直接使用过滤器

    1. <script>
    2. export default {
    3. data(){
    4. return {
    5. name:'zhubajie'
    6. }
    7. }
    8. }
    9. script>

     3.我们在App.vue中引入并映射成组件,运行项目观察效果

    说明
    4. 其实刚刚我们定义了两个id相同的过滤器,但是我们发现局部的并没有改变,于是我们就发现了,过滤器的优先级:局部的要比全局的优先级高;

    3. 串联过滤器

    语法

    {{ message | filterA | filterB }}
    • 后一个过滤器接收的参数为前一个参数的返回值

    实战

    1.在components文件夹下新建FilterSer.vue表示使用串联过滤器,并写上如下代码,直接使用全局过滤器(尾字母大写),和我们自定义的过滤器(首字母大写)

    1. <script>
    2. export default {
    3. data(){
    4. return {
    5. name:'shawujing'
    6. }
    7. },
    8. filters:{
    9. initalWord:function (value) {
    10. if (!value) return ''
    11. value = value.toString()
    12. return value.charAt(0).toUpperCase() + value.slice(1)
    13. }
    14. }
    15. }
    16. script>

     2.我们在App.vue中引入并映射成组件,运行项目观察效果,我们发现两个选择器都使用上了

    4. 过滤器的参数

    语法

    {{ message | filterA('arg1', arg2) }}

    实战

    1. components文件夹下新建FilterParam.vue表示使用过滤器参数,并写上如下代码,定义了一个过滤器,并传递了参数

    1. <script>
    2. export default {
    3. data(){
    4. return {
    5. name:'师徒四人'
    6. }
    7. },
    8. filters:{
    9. paramsFil:function (value,arg1,arg2) {
    10. console.log(value,arg1,arg2)
    11. return value + arg1 + arg2
    12. }
    13. }
    14. }
    15. script>

    我们在App.vue中引入并映射成组件,运行项目观察效果带上了所需要的参数。

    • 通过filterA('arg1', arg2)传入的参数为过滤器的后两个参数

     这个filter已经是非常全了,希望对于各位同仁有一定的帮助,面试如果这样回答关于filter的话,已经非常全了,因为里边包括了空间权重情况,多参数情况,多过滤情况,全面。另外预祝同仁工作顺利,家庭和睦。

  • 相关阅读:
    PYTHON+CH341 3线SPI驱动UC1601 LCD实现汉字显示
    组态数据绑定入门,变量如何暴露给组态编辑
    【C++题解】1302. 是否适合晨练?
    R²决定系数
    Spring整合Mybatis,SqlSessionTemplate方式
    c++ 一个学习小组有5个人,每个人有三门课(高数、英语和C语言)的考试成绩,求每人的平均成绩。按行输出每个学生的各科成绩及平均成绩。
    使用 vue-element-admin 开发后台管理系统【安装】
    软件测试linux面试相关的知识
    scratch还原轨迹 2023年5月中国电子学会图形化编程 少儿编程 scratch编程等级考试四级真题和答案解析
    (一)PHP语法基础——PHP
  • 原文地址:https://blog.csdn.net/2201_75705263/article/details/132896341