原生js处理字符串也能做到vue filter相似效果

119 阅读2分钟

先看效果

let my = '07.8'
let kz = '7.80'
let tx = '07.80'
let wz = '07.8730'
let templateStr = priceRemoveZero`毛衣:¥ ${my} 裤子:${kz} T恤:${tx} 袜子:${wz}`;
console.log(templateStr); // '毛衣:¥ 7.8 裤子:7.8 T恤:7.8 袜子:7.87'

vue filter与原生js对比

vue的filter是主要用于处理常见的文本,可以用在v-bind和双括号语法处,使用方法如下(示例来自vue官网):

<!-- 在双花括号中 -->
{{ message | capitalize }}
​
<!-- 在 `v-bind` 中 -->
<div v-bind:id="rawId | formatId"></div>

和上面原生js对比,发现入参方式有点差别,vue使用|标志数据后面跟的是过滤器,数据类型也有点差异,原生只支持字符串字面量,vue的过滤器不限制数据类型,但对于处理字符串已经足够了。

使用场景

讲几个过滤器的几个实用场景吧,我公司做电商的,所以经常会处理各种价格和图片链接

图片链接处理

图片链接有时候下发的是短链(img/skus/817397979971279.png),有时候下发的是长链,我们在使用的时候会将链接进行一系列处理缩放、降质、协议处理和补全等等,在vue的模版中就可以使用过滤器进行处理,伪代码如下:

{{ img | handleImgUrl }}

使用原生js可以使用以下方式

// 函数实现
handleImgUrl(img)
// 标签化模版实现
handleImgUrl`${protocol}${domain}${img}${quality}`

价格处理

电商对于价格处理也是比较常见的需求,通常价格展示的位置不同,要求也不一样,最常见的是保留两位小数和首尾价格去零,伪代码如下:

vue模版中可以这样:

{{ price | handlePrice }}

使用原生js可以使用以下方式:

// 函数实现
handlePrice(price)
// 标签化模版
handlePrice${price}`

标签化模版

ES6引入了模版字面量,使得js操作字符串变得更灵活,ES6以前字符串的很多操作都不好实现,比如多行;标签化模版就是模版字面量的一个功能,标签化模版本质上就是一个函数,只是函数的参数是固定的,第一个参数是js解释后的字符串数组,后面的参数分别是字面量中的替换位(模版字面量中${}部分),详细可以看以下示例:

function mes(literals, ...substitutions) {
  let result = '';
  // 使用substitutions长度作为循环界限,避免substitutions越界
  for (let i = 0; i < substitutions.length; i++) {
    result += literals[i];
    result += substitutions[i];
  } 
  // 添加最后一个字面量(这里可能有点)
  result += literals[substitutions.length];
  return result;
}
let count = 10,
let price = 0.25,
message = mes`${count} items cost $${(count * price).toFixed(2)}.`;
console.log(message); // "10 items cost $2.50."

从上面示例可以看到替换位的长度总是比字符串字面量的长度少一,也就是literals.length === substitutions.length + 1永远成立

标签化模版实现价格处理

从使用场景的两个示例可以观察出,标签化模版在使用的时候可以更清晰,再有些场景下也会更简洁,可以看一下使用场景中价格处理的实现:

function priceRemoveZero(strArr, ...varArr) {
    let result = '';
    const removeZero = function (price) {
        if (!price || Number.isNaN(parseFloat(price))) return '';
        const priceStr = '' + (+price).toFixed(2);
        return parseFloat(priceStr);
    }
    for (let i = 0, len = varArr.length; i < len; i++) {
        result += strArr[i];
        result += removeZero(varArr[i]); 
    }
    result += strArr[varArr.length];
    return result;
}
​
let price = '088.9530';
priceRemoveZero`¥ ${price}`; // ¥ 88.95

试一下开头的例子:

let my = '07.8'
let kz = '7.80'
let tx = '07.80'
let wz = '07.8730'
let templateStr = priceRemoveZero`毛衣:¥ ${my} 裤子:${kz} T恤:${tx} 袜子:${wz}`;
console.log(templateStr); // '毛衣:¥ 7.8 裤子:7.8 T恤:7.8 袜子:7.87'

可以看出标签化模版在某一些情况下处理字符串比函数更清晰和简洁,当然也看具体场景和个人喜好