专栏名称: SegmentFault思否
SegmentFault (www.sf.gg)开发者社区,是中国年轻开发者喜爱的极客社区,我们为开发者提供最纯粹的技术交流和分享平台。
目录
相关文章推荐
程序员的那些事  ·  快!快!快!DeepSeek 满血版真是快 ·  2 天前  
程序猿  ·  41岁DeepMind天才科学家去世:长期受 ... ·  2 天前  
程序员的那些事  ·  清华大学:DeepSeek + ... ·  3 天前  
程序员小灰  ·  清华大学《DeepSeek学习手册》(全5册) ·  3 天前  
程序员的那些事  ·  惊!小偷“零元购”后竟向 DeepSeek ... ·  4 天前  
51好读  ›  专栏  ›  SegmentFault思否

打造自己的 JavaScript 武器库

SegmentFault思否  · 公众号  · 程序员  · 2017-11-14 08:00

正文

自己打造一把趁手的武器,高效率完成前端业务代码。

前言

作为战斗在业务一线的前端,要想少加班,就要想办法提高工作效率。这里提一个小点,我们在业务开发过程中,经常会重复用到 日期格式化 url参数转对象 浏览器类型判断 节流函数 等一类函数,这些工具类函数,基本上在每个项目都会用到,为避免不同项目多次复制粘贴的麻烦,我们可以统一封装,发布到 npm ,以提高开发效率。

这里,笔者已经封装并发布了自己的武器库 outils,如果你对本项目感兴趣,欢迎 star 本项目。当然你也可以在本项目的基础上封装自己的武器库。

常用函数汇总

这里先分类整理下,之前项目中多次用到的工具函数。

1.Array

1.1 arrayEqual

  1. /**

  2. *

  3. * @desc 判断两个数组是否相等

  4. * @param {Array} arr1

  5. * @param {Array} arr2

  6. * @return {Boolean}

  7. */

  8. function arrayEqual(arr1, arr2) {

  9.    if (arr1 === arr2) return true;

  10.    if (arr1.length != arr2.length) return false;

  11.    for (var i = 0; i < arr1.length; ++i) {

  12.        if (arr1[i] !== arr2[i]) return false;

  13.    }

  14.    return true ;

  15. }

2.Class

2.1 addClass

  1. /**

  2. *

  3. * @desc   为元素添加class

  4. * @param  {HTMLElement} ele

  5. * @param  {String} cls

  6. */

  7. var hasClass = require('./hasClass');

  8. function addClass(ele, cls) {

  9.    if (!hasClass(ele, cls)) {

  10.        ele.className += ' ' + cls;

  11.    }

  12. }

2.2 hasClass

  1. /**

  2. *

  3. * @desc 判断元素是否有某个class

  4. * @param {HTMLElement} ele

  5. * @param {String} cls

  6. * @return {Boolean}

  7. */

  8. function hasClass(ele, cls) {

  9.    return (new RegExp('(\\s|^)' + cls + '(\\s|$)')).test(ele.className);

  10. }

2.3 removeClass

  1. /**

  2. *

  3. * @desc 为元素移除class

  4. * @param {HTMLElement} ele

  5. * @param {String} cls

  6. */

  7. var hasClass = require('./hasClass');

  8. function removeClass(ele, cls) {

  9.    if (hasClass(ele, cls)) {

  10.        var reg = new RegExp('(\\s|^)' + cls + '(\\s|$)');

  11.        ele.className = ele.className.replace(reg, ' ');

  12.    }

  13. }

3.Cookie

3.1 getCookie

  1. /**

  2. *

  3. * @desc 根据name读取cookie

  4. * @param  {String} name

  5. * @return {String}

  6. */

  7. function getCookie(name) {

  8.    var arr = document.cookie.replace(/\s/g, "").split(';');

  9.    for (var i = 0; i < arr.length; i++) {

  10.        var tempArr = arr[i].split('=');

  11.        if (tempArr[0] == name) {

  12.            return decodeURIComponent(tempArr[1]);

  13.        }

  14.    }

  15.     return '';

  16. }

3.2 removeCookie

  1. var setCookie = require('./setCookie');

  2. /**

  3. *

  4. * @desc 根据name删除cookie

  5. * @param  {String} name

  6. */

  7. function removeCookie(name) {

  8.    // 设置已过期,系统会立刻删除cookie

  9.    setCookie(name, '1', -1);

  10. }

3.3 setCookie

  1. /**

  2. *

  3. * @desc  设置Cookie

  4. * @param {String} name

  5. * @param {String} value

  6. * @param {Number} days

  7. */

  8. function setCookie(name, value, days) {

  9.    var date = new Date();

  10.    date.setDate(date.getDate() + days);

  11.    document.cookie = name + '=' + value + ';expires=' + date;

  12. }

4.Device

4.1 getExplore

  1. /**

  2. *

  3. * @desc 获取浏览器类型和版本

  4. * @return {String}

  5. */

  6. function getExplore() {

  7.    var sys = {},

  8.        ua = navigator.userAgent.toLowerCase(),

  9.        s;

  10.    (s = ua.match(/rv:([\d.]+)\) like gecko/ )) ? sys.ie = s[1]:

  11.        (s = ua.match(/msie ([\d\.]+)/)) ? sys.ie = s[1] :

  12.        (s = ua.match(/edge\/([\d\.]+)/)) ? sys.edge = s[1] :

  13.        (s = ua.match(/firefox\/([\d\.]+)/)) ? sys.firefox = s[1] :

  14.        (s = ua.match(/(?:opera|opr).([\d\.]+)/)) ? sys.opera = s[1] :

  15.        (s = ua.match(/chrome\/([\d\.]+)/)) ? sys.chrome = s[1] :

  16.        (s = ua.match(/version\/([\d\.]+).*safari/)) ? sys.safari = s[1] : 0;

  17.    // 根据关系进行判断

  18.     if (sys.ie) return ('IE: ' + sys.ie)

  19.    if (sys.edge) return ('EDGE: ' + sys.edge)

  20.    if (sys.firefox) return ('Firefox: ' + sys.firefox)

  21.    if (sys.chrome) return ('Chrome: ' + sys.chrome)

  22.    if (sys.opera) return ('Opera: ' + sys.opera)

  23.    if (sys.safari) return ('Safari: ' + sys.safari)

  24.    return 'Unkonwn'

  25. }

4.2 getOS

  1. /**

  2. *

  3. * @desc 获取操作系统类型

  4. * @return {String}

  5. */

  6. function getOS() {

  7.    var userAgent = 'navigator' in window && 'userAgent' in navigator && navigator.userAgent.toLowerCase() || '';

  8.    var vendor = 'navigator' in window && 'vendor' in navigator && navigator.vendor.toLowerCase() || '';

  9.    var appVersion = 'navigator' in window && 'appVersion' in navigator && navigator.appVersion.toLowerCase() || '';

  10.    if (/mac/i.test(appVersion)) return 'MacOSX'

  11.    if (/win/i.test(appVersion)) return 'windows'

  12.     if (/linux/i.test(appVersion)) return 'linux'

  13.    if (/iphone/i.test(userAgent) || /ipad/i.test(userAgent) || /ipod/i.test(userAgent)) 'ios'

  14.    if (/android/i.test(userAgent)) return 'android'

  15.    if (/win/i.test(appVersion) && /phone/i.test(userAgent)) return 'windowsPhone'

  16. }

5.Dom

5.1 getScrollTop

  1. /**

  2. *

  3. * @desc 获取滚动条距顶部的距离

  4. */

  5. function getScrollTop() {

  6.    return (document.documentElement && document.documentElement.scrollTop) || document.body.scrollTop;

  7. }

5.2 offset

  1. /**

  2. *

  3. * @desc  获取一个元素的距离文档(document)的位置,类似jQ中的offset()

  4. * @param {HTMLElement} ele

  5. * @returns { {left: number, top: number} }

  6. */

  7. function offset(ele) {

  8.    var pos = {

  9.        left: 0,

  10.        top: 0

  11.    };

  12.    while (ele) {

  13.        pos.left += ele.offsetLeft;

  14.        pos.top += ele.offsetTop;

  15.        ele = ele.offsetParent;

  16.    };

  17.     return pos;

  18. }

5.3 scrollTo

  1. var getScrollTop = require('./getScrollTop');

  2. var setScrollTop = require('./setScrollTop');

  3. var requestAnimFrame = (function () {

  4.    return window.requestAnimationFrame ||

  5.        window.webkitRequestAnimationFrame ||

  6.        window.mozRequestAnimationFrame ||

  7.        function (callback) {

  8.            window.setTimeout(callback, 1000 / 60);

  9.        };

  10. })();

  11. /**

  12. *

  13. * @desc  在${duration}时间内,滚动条平滑滚动到${to}指定位置

  14. * @param {Number} to

  15. * @param {Number} duration

  16. */

  17. function scrollTo(to, duration) {

  18.    if (duration < 0) {

  19.        setScrollTop(to);

  20.        return

  21.    }

  22.     var diff = to - getScrollTop();

  23.    if (diff === 0) return

  24.    var step = diff / duration * 10;

  25.    requestAnimationFrame(

  26.        function () {

  27.            if (Math.abs(step) > Math.abs(diff)) {

  28.                setScrollTop(getScrollTop() + diff);

  29.                 return;

  30.            }

  31.            setScrollTop(getScrollTop() + step);

  32.            if (diff > 0 && getScrollTop() >= to || diff < 0 && getScrollTop() <= to) {

  33.                return;

  34.            }

  35.            scrollTo(to, duration - 16);

  36.        });

  37. }

5.4 setScrollTop

  1. /**

  2. *

  3. * @desc 设置滚动条距顶部的距离

  4. */

  5. function setScrollTop(value) {

  6.    window.scrollTo(0, value);

  7.     return value;

  8. }

6.Keycode

6.1 getKeyName

  1. var keyCodeMap = {

  2.    8: 'Backspace',

  3.    9: 'Tab',

  4.    13: 'Enter',

  5.     16: 'Shift',

  6.    17: 'Ctrl',

  7.    18: 'Alt',

  8.    19: 'Pause',

  9.    20: 'Caps Lock',

  10.    27: 'Escape',

  11.    32 : 'Space',

  12.    33: 'Page Up',

  13.    34: 'Page Down',

  14.    35: 'End',

  15.    36: 'Home',

  16.    37: 'Left',

  17.    38: 'Up',

  18.     39: 'Right',

  19.    40: 'Down',

  20.    42: 'Print Screen',

  21.    45: 'Insert',

  22.    46: 'Delete',

  23.    48: '0',

  24.     49: '1',

  25.    50: '2',

  26.    51: '3',

  27.    52: '4',

  28.    53: '5',

  29.    54: '6',

  30.     55: '7',

  31.    56: '8',

  32.    57: '9',

  33.    65: 'A',

  34.    66: 'B',

  35.     67: 'C',

  36.    68: 'D',

  37.    69: 'E',

  38.    70: 'F',

  39.    71: 'G',

  40.     72: 'H',

  41.    73: 'I',

  42.    74: 'J',

  43.    75: 'K',

  44.    76: 'L',

  45.    77: 'M',

  46.     78: 'N',

  47.    79: 'O',

  48.    80: 'P',

  49.    81: 'Q',

  50.    82: 'R',

  51.     83: 'S',

  52.    84: 'T',

  53.    85: 'U',

  54.    86: 'V',

  55.    87: 'W',

  56.    88: 'X',

  57.    89: 'Y',

  58.    90: 'Z',

  59.    91: 'Windows',

  60.    93: 'Right Click',

  61.    96: 'Numpad 0',

  62.    97: 'Numpad 1',

  63.    98: 'Numpad 2',

  64.    99: 'Numpad 3',

  65.     100: 'Numpad 4',

  66.    101: 'Numpad 5',

  67.    102: 'Numpad 6',

  68.    103: 'Numpad 7',

  69.    104: 'Numpad 8' ,

  70.    105: 'Numpad 9',

  71.    106: 'Numpad *',

  72.    107: 'Numpad +',

  73.    109: 'Numpad -',

  74.     110: 'Numpad .',

  75.    111: 'Numpad /',

  76.    112: 'F1',

  77.    113: 'F2',

  78.     114: 'F3',

  79.    115: 'F4',

  80.    116: 'F5',

  81.    117: 'F6',

  82.     118: 'F7',

  83.    119: 'F8',

  84.    120: 'F9',

  85.    121: 'F10',

  86.     122: 'F11',

  87.    123: 'F12',

  88.    144: 'Num Lock',

  89.    145: 'Scroll Lock',

  90.     182: 'My Computer',

  91.    183: 'My Calculator',

  92.    186: ';',

  93.    187: '=',

  94.     188: ',',

  95.    189: '-',

  96.    190: '.',

  97.    191: '/',

  98.     192: '`',

  99.    219: '[',

  100.    220: '\\',

  101.    221: ']',

  102.     222: '\''

  103. };

  104. /**

  105. * @desc 根据keycode获得键名

  106. * @param  {Number} keycode

  107. * @return {String}

  108. */

  109. function getKeyName(keycode) {

  110.    if (keyCodeMap[keycode]) {

  111.         return keyCodeMap[keycode];

  112.    } else {

  113.        console.log('Unknow Key(Key Code:' + keycode + ')');

  114.        return '';

  115.    }

  116. };

7.Object

7.1 deepClone

  1. /**

  2. * @desc 深拷贝,支持常见类型

  3. * @param {Any} values

  4. */

  5. function deepClone(values) {

  6.     var copy;

  7.    // Handle the 3 simple types, and null or undefined

  8.    if (null == values || "object" != typeof values) return values;

  9.    // Handle Date

  10.    if (values instanceof Date) {

  11.        copy = new Date();

  12.        copy.setTime(values.getTime());

  13.        return copy;

  14.    }

  15.     // Handle Array

  16.    if (values instanceof Array) {

  17.        copy = [];

  18.         for (var i = 0, len = values.length; i < len; i++) {

  19.            copy[i] = deepClone(values[i]);

  20.        }

  21.        return copy;

  22.    }

  23.    // Handle Object

  24.    if (values instanceof Object) {

  25.        copy = {};

  26.        for (var attr in values) {

  27.            if (values.hasOwnProperty(attr)) copy[attr] = deepClone(values[attr]);

  28.        }

  29.        return copy;

  30.    }

  31.    throw new Error("Unable to copy values! Its type isn't supported.");

  32. }

7.2 isEmptyObject

  1. /**

  2. *

  3. * @desc   判断`obj`是否为空

  4. * @param  {Object} obj

  5. * @return {Boolean}

  6. */

  7. function isEmptyObject(obj) {

  8.    if (!obj || typeof obj !== 'object' || Array.isArray(obj))

  9.        return false

  10.     return !Object.keys(obj).length

  11. }

8.Random

8.1 randomColor

  1. /**

  2. *

  3. * @desc 随机生成颜色

  4. * @return {String}

  5. */

  6. function randomColor() {

  7.     return '#' + ('00000' + (Math.random() * 0x1000000 << 0).toString(16)).slice(-6);

  8. }

8.2 randomNum

  1. /**

  2. *

  3. * @desc 生成指定范围随机数

  4. * @param  {Number} min

  5. * @param  {Number} max

  6. * @return {Number}

  7. */

  8. function randomNum(min, max) {

  9.    return Math.floor(min + Math.random() * (max - min));

  10. }

9.Regexp

9.1 isEmail

  1. /**

  2. *

  3. * @desc   判断是否为邮箱地址

  4. * @param  {String}  str

  5. * @return {Boolean}

  6. */

  7. function isEmail(str) {

  8.    return /\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*/.test(str);

  9. }

9.2 isIdCard

  1. /**

  2. *

  3. * @desc  判断是否为身份证号

  4. * @param  {String|Number} str

  5. * @return {Boolean}

  6. */

  7. function isIdCard(str) {

  8.    return /^(^[1-9]\d{7}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}$)|(^[1-9]\d{5}[1-9]\d{3}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])((\d{4})|\d{3}[Xx])$)$/.test(str)

  9. }

9.3 isPhoneNum

  1. /**

  2. *

  3. * @desc   判断是否为手机号

  4. * @param  {String|Number} str

  5. * @return {Boolean}

  6. */

  7. function isPhoneNum(str) {

  8.     return /^(0|86|17951)?(13[0-9]|15[012356789]|17[678]|18[0-9]|14[57])[0-9]{8}$/.test(str)

  9. }

9.4 isUrl

  1. /**

  2. *

  3. * @desc   判断是否为URL地址

  4. * @param  {String} str

  5. * @return {Boolean}

  6. */

  7. function isUrl(str) {

  8.     return /[-a-zA-Z0-9@:%._\+~#=]{2,256}\.[a-z]{2,6}\b([-a-zA-Z0-9@:%_\+.~#?&//=]*)/i.test(str);

  9. }

10.String

10.1 digitUppercase

  1. /**

  2. *

  3. * @desc   现金额转大写

  4. * @param  {Number} n

  5. * @return {String}

  6. */

  7. function digitUppercase(n) {

  8.    var fraction = ['角', '分'];

  9.    var digit = [

  10.         '零', '壹', '贰', '叁', '肆',

  11.        '伍', '陆', '柒', '捌', '玖'

  12.    ];

  13.     var unit = [

  14.        ['元', '万', '亿'],

  15.        ['', '拾', '佰', '仟']

  16.    ];

  17.    var head = n < 0 ? '欠' : '';

  18.    n = Math.abs(n);

  19.     var s = '';

  20.    for (var i = 0; i < fraction.length; i++) {

  21.        s += (digit[Math.floor(n * 10 * Math.pow(10, i)) % 10] + fraction[i]).replace(/零./, '');

  22.    }

  23.    s = s || '整';

  24.    n = Math.floor(n);

  25.     for (var i = 0; i < unit[0].length && n > 0; i++) {

  26.        var p = '';

  27.        for (var j = 0; j < unit[1].length && n > 0; j++) {

  28.            p = digit[n % 10] + unit[1][j] + p;

  29.            n = Math.floor(n / 10);

  30.        }

  31.        s = p.replace( /(零.)*零$/, '').replace(/^$/, '零') + unit[0][i] + s;

  32.    }

  33.    return head + s.replace(/(零.)*零元/, '元')

  34.        .replace( /(零.)+/g, '零')

  35.        .replace(/^整$/, '零元整');

  36. };

11.Support

11.1 isSupportWebP

  1. /**

  2. *

  3. * @desc 判断浏览器是否支持webP格式图片

  4. * @return {Boolean}

  5. */

  6. function isSupportWebP() {

  7.    return !![].map && document.createElement('canvas').toDataURL('image/webp').indexOf('data:image/webp') == 0;

  8. }

12.Time

12.1 formatPassTime

  1. /**

  2. * @desc   格式化${startTime}距现在的已过时间

  3. * @param  {Date} startTime

  4. * @return {String}

  5. */

  6. function formatPassTime(startTime) {

  7.    var currentTime = Date.parse(new Date()),

  8.        time = currentTime - startTime,

  9.        day = parseInt(time / (1000 * 60 * 60 * 24)),

  10.        hour = parseInt(time / (1000 * 60 * 60)),

  11.        min = parseInt(time / ( 1000 * 60)),

  12.        month = parseInt(day / 30),

  13.        year = parseInt(month / 12);

  14.     if (year) return year + "年前"

  15.    if (month) return month + "个月前"

  16.    if (day) return day + "天前"

  17.     if (hour) return hour + "小时前"

  18.    if (min) return min + "分钟前"

  19.    else return '刚刚'

  20. }

12.2 formatRemainTime

  1. /**

  2. *

  3. * @desc   格式化现在距${endTime}的剩余时间

  4. * @param  {Date} endTime  

  5. * @return {String}

  6. */

  7. function formatRemainTime(endTime) {

  8.    var startDate = new Date(); //开始时间

  9.     var endDate = new Date(endTime); //结束时间

  10.    var t = endDate.getTime() - startDate.getTime(); //时间差

  11.    var d = 0,

  12.        h = 0,

  13.        m = 0,

  14.        s = 0;

  15.     if (t >= 0) {

  16.        d = Math.floor(t / 1000 / 3600 / 24);

  17.        h = Math.floor(t / 1000 / 60 / 60 % 24);

  18.        m = Math.floor(t / 1000 / 60 % 60);

  19.        s = Math.floor(t / 1000 % 60);

  20.    }

  21.     return d + "天 " + h + "小时 " + m + "分钟 " + s + "秒";

  22. }

13.Url

13.1 parseQueryString

  1. /**

  2. *

  3. * @desc   url参数转对象

  4. * @param  {String} url  default: window.location.href

  5. * @return {Object}

  6. */

  7. function parseQueryString(url) {

  8.    url = url == null ? window.location.href : url

  9.    var search = url.substring(url.lastIndexOf('?') + 1)

  10.     if (!search) {

  11.        return {}

  12.    }

  13.     return JSON.parse('{"' + decodeURIComponent(search).replace(/"/g, '\\"').replace(/&/g, '","').replace(/=/g, '":"') + '"}')

  14. }

13.2 stringfyQueryString

  1. /**

  2. *

  3. * @desc   对象序列化

  4. * @param  {Object} obj

  5. * @return {String}

  6. */

  7. function stringfyQueryString(obj) {

  8.    if (!obj) return '';

  9.    var pairs = [];

  10.     for (var key in obj) {

  11.        var value = obj[key];

  12.         if (value instanceof Array) {

  13.            for (var i = 0; i < value.length; ++i) {

  14.                pairs.push(encodeURIComponent(key + '[' + i + ']') + '=' + encodeURIComponent(value[i]));

  15.            }

  16.            continue;

  17.        }

  18.        pairs.push(encodeURIComponent(key) + '=' + encodeURIComponent(obj[key]));

  19.    }

  20.    return pairs.join('&');

  21. }

14.Function

14.1 throttle

  1. /**

  2. * @desc   函数节流。

  3. * 适用于限制`resize`和`scroll`等函数的调用频率

  4. *

  5. * @param  {Number}    delay          0 或者更大的毫秒数。 对于事件回调,大约100或250毫秒(或更高)的延迟是最有用的。

  6. * @param  {Boolean}   noTrailing     可选,默认为false。

  7. *                                    如果noTrailing为true,当节流函数被调用,每过`delay`毫秒`callback`也将执行一次。

  8. *                                    如果noTrailing为false或者未传入,`callback`将在最后一次调用节流函数后再执行一次.

  9. *                                    (延迟`delay`毫秒之后,节流函数没有被调用,内部计数器会复位)

  10. * @param  {Function}  callback       延迟毫秒后执行的函数。`this`上下文和所有参数都是按原样传递的,

  11. *                                    执行去节流功能时,调用`callback`。

  12. * @param  {Boolean}   debounceMode   如果`debounceMode`为true,`clear`在`delay`ms后执行。

  13. *                                    如果debounceMode是false,`callback`在`delay` ms之后执行。

  14. *

  15. * @return {Function}  新的节流函数

  16. */

  17. function throttle(delay, noTrailing, callback, debounceMode) {

  18.    // After wrapper has stopped being called, this timeout ensures that

  19.    // `callback` is executed at the proper times in `throttle` and `end`

  20.    // debounce modes.

  21.     var timeoutID;

  22.    // Keep track of the last time `callback` was executed.

  23.     var lastExec = 0;

  24.     // `noTrailing` defaults to falsy.

  25.    if (typeof noTrailing !== 'boolean') {

  26.        debounceMode = callback;

  27.        callback = noTrailing;

  28.        noTrailing = undefined;

  29.    }

  30.     // The `wrapper` function encapsulates all of the throttling / debouncing

  31.    // functionality and when executed will limit the rate at which `callback`

  32.     // is executed.

  33.    function wrapper() {

  34.         var self = this;

  35.        var elapsed = Number(new Date()) - lastExec;

  36.         var args = arguments;

  37.         // Execute `callback` and update the `lastExec` timestamp.

  38.        function exec() {

  39.            lastExec = Number(new







请到「今天看啥」查看全文