Interview question three: Please talk about the implementation of the filter function in Vue

The use of filters in Vue

Let’s think about why there is a filter when there are methods, because the implementation efficiency of filter is much higher than that of methods.

Take a look at the official definition:

Vue.js allows you to customize filters that can be used for some common text formatting. Filters can be used in two places: double curly brace interpolation and v-bind expressions (the latter is supported starting from 2.1.0+). Filters should be added at the end of the JavaScript expression, indicated by the "pipe" symbol:

1. Local filter (most frequently used)

grammar

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

After one operation, the above filter will become: _s(_f("capitalize")(message)).

_f: This function is actually an alias of resolveFilter. Its function is to find the filter from _this.$options.filter and return it.
_s: This function is an alias of the toString function. Its function is to get the filtered result and pass it to the toString() function. , the result will be saved to the text attribute in the VNode, and the result will be returned to render the view directly.
 

The principle of _f function 

The _f function actually looks for the filter. If the filter is found, it returns the filter. If it is not found, it returns the same value as the parameter. Its code is actually very simple:

import {identity, resolveAssets} from 'core/util/index'

export function resolveFilter(id){
  return resolveAssets(this.$options, 'filters', id, true) || identity
}

Let's focus on what resolveAssets does.

export function resolveAsset (options, type, id, warnMissing){
  if(typeof(id) !== 'string'){
    return
  }
  
  const assets = options[type]
  if(hasOwn(assets, id)) return assets[id]
  const camelizedId = camelize(id)
  if(hasOwn(assets, camelizedId)) return assets[camelizedId]
  const PascalCaseId = capitlize(camelizedId)
  if(hasOwn(assets, PascalCaseId)) return assets[PascalCaseId]
  
  //检查原型链
  const res assets[id] || assets[camelizedId] || PascalCaseId
  if(process.env.NODE_ENV!=='production'&& warnMissing&&!res){
    warn('Fail to resolve' + type.slice(0,-1)+':'+id, options)
  }
  return res
}

In fact, its search process is also very simple, mainly doing the following operations (id is the filter id):

1. Determine whether the filter id is a string, if not, terminate.
2. Use assets to store the filter. 3.
The hasOwn function checks whether the assets themselves have an id attribute. If it does, it returns.
4. The hasOwn function checks whether the assets themselves have a camel-case id. Attribute, if it exists, it returns
5. The hasOwn function checks whether the assets themselves have the id attribute with the first letter capitalized. If it exists, it returns
6. If it still does not exist, go to the prototype chain to find it. If it cannot find it, a warning will be printed.

Filter analysis principle

Let's think about it, how does the parser parse the syntax of the filter? In fact, there is such a function inside Vue to parse filter syntax:parseFilters

Its principle is to parse the filter list and then 循环过滤器列表merge it 拼接字符串.

  • script
filter:{
    judgeRole(val) {
      if (val === '0') {
        return '平台'
      } else if (val === '1') {
        return '企业'
      } else if (val === '2') {
        return '企业用户'
      } else {
        return ''
      }
    }

}

illustrate

  • in the filter function valueis  |the previous value, which is equivalent to the first parameter
  • A value must be returned in the filter function, which is the result of our format processing
  • In layman's terms, when a filter is bound to a piece of data, it will call the function of the corresponding filter every time the data is rendered.

Actual combat

Use vue-cli to download a default project. I use vue/cli4the default directory as follows 

1. componentsCreate a new local filter under the folder FilterLoc.vueand write the following code. Our purpose is to change the sunwukongfirst letter to uppercase

<template>
    <div>{
   
   {name | capitalize}}</div>
</template>

<script>
export default {
    data(){
        return {
            name:'sunwukong'
        }
    },
    filters:{
        //当value改变的时候,他会执行这个函数
        capitalize:function (value) {
            //一定要返回一个值才能在组件中正常显示
            if (!value) return ''
            value = value.toString()
            return value.charAt(0).toUpperCase() + value.slice(1)
        }
    }
}
</script>

2. We App.vueintroduce it in and map it into components

<template>
    <div><filter-loc></filter-loc></div>
</template>

<script>
import FilterLoc from '@/components/FilterLoc'
export default {
    components:{
        FilterLoc
    }
}
</script>

3. Run the project and observe the effect. sunwukongThe first has been capitalized.

2. Global filter

1. We can define global filters in the entry file, or in other files. Here we change the last initial letter to uppercase.

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

2. componentsCreate a new one under the folder FilterGlo.vueto use the global filter, and write the following code to use the filter directly.

<template>
    <div>{
   
   {name | capitalize}}</div>
</template>

<script>
export default {
    data(){
        return {
            name:'zhubajie'
        }
    }
}
</script>

 3. We App.vueintroduce and map it into components, run the project to observe the effect

Note
4. In fact, we just defined two ididentical filters, but we found that the local one has not changed, so we discovered that the priority of the filter: the local one has a higher priority than the global one;

3. In-line filters

grammar

<div>{
   
   { message | filterA | filterB }}</div>
  • The parameter received by the latter filter is the return value of the previous parameter.

Actual combat

1. componentsCreate a new one under the folder FilterSer.vueto use the serial filter, and write the following code to directly use the global filter (the last letter is capitalized), and our custom filter (the first letter is capitalized)

<template>
    <div>{
   
   {name|initalWord|capitalize}}</div>
</template>

<script>
export default {
    data(){
        return {
            name:'shawujing'
        }
    },
    filters:{
        initalWord:function (value) {
            if (!value) return ''
            value = value.toString()
            return value.charAt(0).toUpperCase() + value.slice(1)
        }
    }
}
</script>

 2. We App.vueintroduced and mapped it into components, ran the project to observe the effect, and found that both selectors were used.

4. Filter parameters

grammar

<div>{
   
   { message | filterA('arg1', arg2) }}</div>

Actual combat

  1. Create a new one under componentsthe folder FilterParam.vueto use filter parameters, and write the following code to define a filter and pass the parameters.

<template>
    <div>{
   
   {name|paramsFil('白骨精','白龙马')}}</div>
</template>

<script>
export default {
    data(){
        return {
            name:'师徒四人'
        }
    },
    filters:{
        paramsFil:function (value,arg1,arg2) {
            console.log(value,arg1,arg2)
            return value + arg1 + arg2
        }
    }
}
</script>

We App.vueintroduced it in and mapped it into components, and ran the project to observe the effect with the required parameters.

  • The parameters passed in are filterA('arg1', arg2)the last two parameters of the filter.

 This filter is already very comprehensive, and I hope it will be of some help to all colleagues. If you answer this question about the filter in the interview, it is already very comprehensive, because it includes spatial weight conditions, multi-parameter conditions, and multi-filter conditions, comprehensively. I also wish my colleagues success in their work and harmony in their families.

Guess you like

Origin blog.csdn.net/2201_75705263/article/details/132896341