Vuejs 过滤器进阶,以及当 filterBy 无法满足需求时自定义特殊过滤的方法

过滤器的使用

  1. 字符串显示

     {{value | filterid args}}
    
  2. HTML显示

     {{{value | filterid args}}}
    
  3. 函数包装处理器

     <input @keyup="onKeyup | filterid args">
    
  4. 数组过滤器

     <div v-for="item in items | filterid args"></div>
    
  5. 过滤器允许管道接驳

     {{value | filterone args | filtertow args | filterthree args}}
    

官方自带过滤器

  1. capitalize,首字母自动大写

     {{ msg | capitalize }}
     // ‘abc’ => ‘Abc’
    
  2. uppercase,全字母大写

     {{ msg | uppercase }}
     // ‘abc’ => ‘ABC’
    
  3. lowercase,全字母小写

     {{ msg | lowercase }}
     // ‘ABC’ => ‘abc’
    
  4. currency,货币格式化,参数一是货币符号,参数二是保留小数位

     {{ amount | currency }}
     // 12345 => $12,345.00
    
     {{ amount | currency '£' }}
     // 12345 => £12,345.00
    
     {{ amount | currency '₫' 0 }}
     // 12345 => ₫12,345
    
  5. pluralize,数量复数,自行补充s或其他复数形式

     {{count}} {{count | pluralize 'item' }}
     // 1 => ‘1 item’
     // 2 => ‘2 items’
    
     {{count}} {{count | pluralize 'st' 'nd' 'rd' 'th' }}
     // 1 => ‘1st’
     // 2 => ‘2nd’
     // 3 => ‘3rd’
     // 4 => ‘4th’
     // 5 => ‘5th’
    
  6. json,JSON格式化,允许一个整型参数,表示格式化时的缩进量

     {{ nestedObject | json 4 }}
    
  7. debounce,函数过滤器,用于延迟执行

     <input @keyup="onKeyup | debounce 500">
    
  8. limitBy,数组过滤器,用于限制数组的数量和偏移量

    http://vuejs.org.cn/api/#limitBy

  9. filterBy,数组过滤器,用于搜索数组,保留符合条件的元素,良好支持对象过滤

    http://vuejs.org.cn/api/#filterBy

    下文有进阶阅读:自定义filterBy过滤函数

  10. orderBy,数组过滤器,用于对数组进行排序,良好支持对象排序

    http://vuejs.org.cn/api/#orderBy

    下文有进阶阅读:自定义orderBy过滤函数

自定义过滤器

原始的自定义过滤器的创建方法如下:

Vue.filter('filterid', function (value) {
  return dosomething(value)
}

function第一个参数是要过滤的值,后面的参数是在过滤后跟着的,数量自定义,例如以下是我写的字符长度限制过滤器:

Vue.filter('maxlength', function (value, maxlen, ellipsis = '...') {
  let len = 0
  let i = 0
  for (i = 0; i < value.length && len <= maxlen; i++) {
    if (value.charCodeAt(i) > 127 || value.charCodeAt(i) === 94) {
      // 中文
      len += 2
    } else {
      // 非中文
      len++
    }
  }
  if (i >= value.length) {
    // 没有截取
    return value
  } else if (!ellipsis || ellipsis === '') {
    // 截取不补充
    return value.substr(0, i - 1)
  } else {
    // 截取并补充
    return value.substr(0, i - 1 - ellipsis.length) + ellipsis
  }
})

使用:

{{article.summary | maxlength 50}}
{{article.summary | maxlength 50 '…'}}

单文件模式中,过滤器以函数的形式定义在 filters 中:

<script>
export default {
  filters: {
    filterid: function (value) {
      return dosomething(value)
    }
  }
}
</script>

自定义双向过滤器

来直接看官方例子

Vue.filter('currencyDisplay', {
  // model -> view
  // 在更新 `<input>` 元素之前格式化值
  read: function(val) {
    return '$'+val.toFixed(2)
  },
  // view -> model
  // 在写回数据之前格式化值
  write: function(val, oldVal) {
    var number = +val.replace(/[^\d.]/g, '')
    return isNaN(number) ? 0 : parseFloat(number.toFixed(2))
  }
})

过滤器用于input时,write后会马上read,read更多是用来修复write后的显示,目的在于隐藏实际数值,使其对用户友好。结合上面的官方例子,write方法令用户的输入最终转成一个两位小数来保存,read方法令用户看到的最终是货币符号后跟两位小数。

自定义 filterBy 过滤器

filterBy的过滤函数,不允许传入更多的参数,返回值要是boolean类型,true表示符合条件,false表示不符合条件,简单例子:

// template:
<li v-for="item in items | filterBy female">{{item | json 4}}</li>

// script:
<script>
export default {
  methods: {
    female: function (obj) {
      return obj.sex === 0
    }
  }
}
</script>

当然这个例子不需自定义函数那么麻烦,但特殊过滤方案时就需要用到,比如现在要获取用户对象中固话和手机中只有一个为空的用户的列表

自定义 orderBy 过滤器

orderBy的过滤函数,允许带一个参数,1表示正序,-1表示倒序,返回值要是integer类型,与js的sort类似,负数表示小于,0表示相等,1表示大于,正序为从小到大,简单例子:

// template:
<li v-for="item in items | orderBy byage -1">{{item | json 4}}</li>

// script:
<script>
export default {
  methods: {
    byage: function (a, b) {
      return a.age - b.age
    }
  }
}
</script>

当然这个例子不需自定义函数那么麻烦,但特殊排序方案时就需要用到,比如搜索时需要根据相似度排序

自定义 数组过滤器

当limitBy,filterBy,orderBy都无法满足需求时,我们还可以自定义一个数组过滤器,这是一个终极方案,几乎能解决所有筛选相关的问题。

以下是filterBy的源码,建议阅读,是写好一个数组过滤器的很好的学习对象

export function filterBy (arr, search, delimiter) {
  arr = convertArray(arr)
  if (search == null) {
    return arr
  }
  if (typeof search === 'function') {
    return arr.filter(search)
  }
  // cast to lowercase string
  search = ('' + search).toLowerCase()
  // allow optional `in` delimiter
  // because why not
  var n = delimiter === 'in' ? 3 : 2
  // extract and flatten keys
  var keys = Array.prototype.concat.apply([], toArray(arguments, n))
  var res = []
  var item, key, val, j
  for (var i = 0, l = arr.length; i < l; i++) {
    item = arr[i]
    val = (item && item.$value) || item
    j = keys.length
    if (j) {
      while (j--) {
        key = keys[j]
        if ((key === '$key' && contains(item.$key, search)) ||
            contains(getPath(val, key), search)) {
          res.push(item)
          break
        }
      }
    } else if (contains(item, search)) {
      res.push(item)
    }
  }
  return res
}

定义方法与普通的过滤器定义一样,第一个参数固定是要过滤的数组,其他参数自定义,不限制数量,允许是动态参数:

Vue.filter('customFilter', function (array, args) {
	return dosomething(array)
})

这里我有一个需求,我有一个会话列表,但有一些会话是不需要显示的,会话是否显示取决于另一个数组中是否有该会话的ID,若简单实现,filterBy自定义函数即可,但把这种情况复杂化,做一个in数组的过滤器,以后还会有用处:

filterIn: function (arr, key, enableVals) {
 let result = []
 for (let i = 0; i < arr.length; i++) {
   if (enableVals.indexOf(arr[i][key]) > -1) {
     result.push(arr[i])
   }
 }
 return result
}

使用:

// template:
<li v-for="item in items | filterIn 'id' enableIds">{{item | json}}</li>

// script:
<script>
export default {
  data () {
    return {
      items: [
        {
          id: 10001,
          name: 'Jason',
          age: 18
        },
        {
          id: 10002,
          name: 'Andrew',
          age: 29
        },
        {
          id: 10003,
          name: 'Winson',
          age: 22
        },
        {
          id: 10004,
          name: 'Li',
          age: 19
        }
      ],
      enableIds: [10002, 10003, 10006, 10012]
    }
  }
}
</script>
若您觉得我的博文对您有帮助,欢迎点击下方按钮对我打赏
打赏