前言 | 问题背景

在不同的应用场景中,数字格式千变万化,即便强大如Excel,也无法满足所有的数字格式的需求。有用户提出了这样的需求:小数超过两位时,只保留两位且不做进位(例如123.456显示123.45);小数不足两位时,无后缀0(例如123.4就显示123.4);没有小数时只显示整数(例如123就显示123);整数部分需要能够每三位添加一个分位符(例如1234显示1,234)。

本文基于SpreadJS V12版本,下载请点击

问题分析与解决思路

针对这样的“非典型需求”,我们即无法直接用Excel实现,Spread JS也没有原生的数字格式的支持。原本用户想用条件格式来实现,但实际上Spread JS提供了更加简洁的思路——自定义格式接口,这样用户可以最大限度地实现自己想要的格式。

在官网的学习指南上,有一个简单的示例,感兴趣的可以先移步参考:

https://demo.grapecity.com.cn/SpreadJS/TutorialSample/#/demos/customFormatter

解决自定义格式的问题,可以分为以下几个步骤:

  1. 重写GC.Spread.Formatter.GeneralFormatter类的format方法,这个方法接收的第一个参数就是单元格的值,我们可以在format方法中随意拼接修改值的格式和内容,不会影响单元格的真实值,只会改变最终的展示格式(单元格的Text)。
  2. 为单元格设置自定义样式。
  3. 定义一个处理数字的方法,返回符合上述用户需求的数字字符串。示例中提供的方法比需求的更强大和灵活,不仅可以实现定制是否四舍五入,还可以自定义分位符与小数点。

示例代码分析

示例中主要做了两件事,一是通过继承GeneralFormatter类来实现自定义数字格式,二是在format方法中实现了自定义数字格式的业务逻辑。下面的代码部分就是第一步,如何通过继承GeneralFormatter来实现自定义数字格式。

var customFormatterTest = {};
customFormatterTest.prototype = GC.Spread.Formatter.GeneralFormatter;
// format方法中,第一个参数obj就是当前单元格的值(带类型)
customFormatterTest.format = function (obj, conditionalForeColor) {
    return number_format(obj, 2, ".", ",");
};

上述代码通过继承GeneralFormatter类,并重写format方法实现了自定义数字格式,在format方法中,第一个参数obj就是当前单元格的值,拿到单元格的值后,可以根据业务需求进行自定义显示格式,方法返回值是一个字符串。

第二部,实现自定义数字格式,注意最后返回值是字符串就行了。

function number_format(number, decimals, dec_point, thousands_sep, isRoundUp) {
    /*
    * 参数说明:
    * number:要格式化的数字
    * decimals:保留几位小数
    * dec_point:小数点符号
    * thousands_sep:千分位符号
    * isRoundUp:是否四舍五入
    * */
    number = (number + '').replace(/[^0-9+-Ee.]/g, '');
    var n = !isFinite(+number) ? 0 : +number,
        prec = !isFinite(+decimals) ? 0 : Math.abs(decimals),
        sep = (typeof thousands_sep === 'undefined') ? ',' : thousands_sep,
        dec = (typeof dec_point === 'undefined') ? '.' : dec_point,
        s = '',
        toFixedFix = function (n, prec) {
            var k = Math.pow(10, prec);
            // 是否四舍五入
            if(isRoundUp){
                return '' + Math.round(n * k) / k;
            }
            // floor 实现了只舍去不进位的逻辑
            return '' + Math.floor(n * k) / k;
        };
    s = (prec ? toFixedFix(n, prec) : '' + Math.round(n)).split('.');
    var re = /(-?\d+)(\d{3})/;
    while (re.test(s[0])) {
        s[0] = s[0].replace(re, "$1" + sep + "$2");
    }

    if ((s[1] || '').length < prec) {
        s[1] = s[1] || '';
    }
    // 当小数部分为空时,不显示小数点
    if(s[1] === ""){
        return s.join("");
    }
    return s.join(dec);
}

完整版的Demo,请点击此处下载