工具函数
String
contains
function contains (target, str, separator) {
return separator ? (separator + target + separator).indexOf(separator + str + separator) > -1 : target.indexOf(str) > -1;
}
startsWith
function startsWith (target, str, ignorecase) {
var start_str = target.substr(0, str.length);
return ignorecase ? start_str.toLowerCase() === str.toLowerCase() : start_str === str;
}
endsWith
function endsWith (target, str, ignorecase) {
var end_str = target.substring(target.length - str.length);
return ignorecase ? end_str.toLowerCase() === str.toLowerCase() : end_str === str;
}
repeat
function repeat (target, n) {
var s = target,
total = "";
while (n > 0) {
if (n % 2 == 1)
total += s;
if (n == 1)
break;
s += s;
n = n >> 1;
}
return total;
}
byteLen
byteLen: 取得一个字符串所有字节的长度(来自腾讯的解决方案。腾讯通过多子域名+postMessage+manifest 离线 proxy 页面的 方式扩大 localStorage 的存储空间,在这过程中需要知道用户已经存了多少东西,因此,我们就 必须编写一个严谨的 byteLen 方法。)
/** *
* http://www.alloyteam.com/2013/12/js-calculate-the-number-of-bytes-occupied-by-a-str ing/
* 计算字符串所占的内存字节数,默认使用 UTF-8 的编码方式计算,也可制定为 UTF-16
* UTF-8 是一种可变长度的 Unicode 编码格式,使用 1 至 4 个字节为每个字符编码 *
* 000000 - 00007F(128个代码)
* 000080 - 0007FF(1920个代码)
* 000800 - 00D7FF 00E000 - 00FFFF(61440个代码) 0zzzzzzz(00-7F) 一个字节 110yyyyy(C0-DF) 10zzzzzz(80-BF) 两个字节 1110xxxx(E0-EF) 10yyyyyy 10zzzzzz 3个字节
* 010000 - 10FFFF(1048576 个代码) 11110www(F0-F7) 10xxxxxx 10yyyyyy 10zzzzzz 4 个字节 *
* 注: Unicode 在范围 D800-DFFF 中不存在任何字符
* {@link <a onclick="javascript:pageTracker._trackPageview('/outgoing/zh.wikipedia.org/wiki/UTF -8');"
* href="http://zh.wikipedia.org/wiki/UTF-8">http://zh.wikipedia.org/wiki/UTF-8</a>} *
* UTF-16 大部分使用两个字节编码,编码超出 65535 的使用 4 个字节
* 000000 - 00FFFF 两个字节
* 010000 - 10FFFF 4 个字节
* {@link <a onclick="javascript:pageTracker._trackPageview('/outgoing/zh.wikipedia.org/wiki/UTF-16');"
* href="http://zh.wikipedia.org/wiki/UTF-16">http://zh.wikipedia.org/wiki/UTF-16</a>} * @param {String} str
* @param {String} charset utf-8, utf-16
* @return {Number}
*/
function byteLen(str, charset) {
var total = 0,
charCode,
i,
len;
charset = charset ? charset.toLowerCase() : '';
if (charset === 'utf-16' || charset === 'utf16') {
for (i = 0, len = str.length; i < len; i++) {
charCode = str.charCodeAt(i);
if (charCode <= 0xffff) {
total += 2;
} else {
total += 4;
}
}
} else {
for (i = 0, len = str.length; i < len; i++) {
charCode = str.charCodeAt(i);
if (charCode <= 0x007f) {
total += 1;
} else if (charCode <= 0x07ff) {
total += 2;
} else if (charCode <= 0xffff) {
total += 3;
} else {
total += 4;
}
}
}
return total;
}
truncate
用于对字符串进行截断处理,当超过限定长度,默认添加三个点号。
function truncate (target, length, truncation) {
length = length || 30;
truncation = truncation === void(0) ? '...' : truncation;
return target.length > length ? target.slice(0, length - truncation.length) + truncation : String(target);
}
camelize
转换为驼峰风格
function camelize (target) {
if (target.indexOf('-') < 0 && target.indexOf('_') < 0) {
return target; //提前判断,提高getStyle等的效率
}
return target.replace(/[-_][^-_]/g, function(match) {
return match.charAt(1).toUpperCase();
});
}
underscored
转换为下划线风格
function underscored (target) {
return target.replace(/([a-z\d])([A-Z])/g, '$1_$2').
replace(/\-/g, '_').toLowerCase();
}
dasherize
function dasherize (target) {
return underscored(target).replace(/_/g, '-');
}
capitalize
首字母大写
function capitalize(target) {
return target.charAt(0).toUpperCase() + target.substring(1).toLowerCase();
}
stripTags
移除字符串中的 html 标签,但这方法有缺陷,如里面有 script 标签,会把这 些不该显示出来的脚本也显示出来。在 Prototype.js 中,它与 strip、stripScripts 是一组方法。
function stripTags (target) {
return String(target || "").replace(/<[^>]+>/g, '');
}
stripScripts
移除字符串中所有的 script 标签。弥补 stripTags 方法的缺陷。此方法应 在 stripTags 之前调用。
function stripScripts (target) {
return String(target || "").replace(/<script[^>]*>([\S\s]*?)<\/script>/img, '')
}
escapeHTML
将字符串经过 html 转义得到适合在页面中显示的内容,如将<替换 为 <。
function escapeHTML (target) {
return target.replace(/&/g, '&')
.replace(/</g, '<')
.replace(/>/g, '>')
.replace(/"/g, """)
.replace(/'/g, "'");
}
unescapeHTML
将字符串中的 html 实体字符还原为对应字符。
function escapeHTML (target) {
return target.replace(/&/g, '&')
.replace(/</g, '<')
.replace(/>/g, '>')
.replace(/"/g, """)
.replace(/'/g, "'"); //IE下不支持'(单引号)转义
}
escapeRegExp
function escapeRegExp (target) {
return target.replace(/([-.*+?^${}()|[\]\/\\])/g, '\\$1');
}
trim
// 简洁
function trim (str) {
return str.replace(/^\s+|\s+$/g, '');
}
function trim (string) {
// uFEFF:字节顺序标记(英语:byte-order mark,BOM)是位于码点U+FEFF的统一码字符的名称。当以UTF-16或UTF-32来将UCS/统一码字符所组成的字符串编码时,这个字符被用来标示其字节序。它常被用来当做标示文件是以UTF-8、UTF-16或UTF-32编码的记号。
return (string || '').replace(/^[\s\uFEFF]+|[\s\uFEFF]+$/g, '');
};
// 速度快
function trim (str) {
var whitespace = ' \n\r\t\f\x0b\xa0\u2000\u2001\u2002\u2003\n\
\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u200b\u2028\u2029\u3000';
for (var i = 0; i < str.length; i++) {
if (whitespace.indexOf(str.charAt(i)) === -1) {
str = str.substring(i);
break;
}
}
for (i = str.length - 1; i >= 0; i--) {
if (whitespace.indexOf(str.charAt(i)) === -1) {
str = str.substring(0, i + 1);
break;
}
}
return whitespace.indexOf(str.charAt(0)) === -1 ? str : '';
}
pad
与 trim 相反,pad 可以为字符串的某一端添加字符串。
function pad (target, n, filling, right, radix) {
var num = target.toString(radix || 10);
filling = filling || "0";
while (num.length < n) {
if (!right) {
num = filling + num;
} else {
num += filling;
}
}
return num;
}
wbr
为目标字符串添加 wbr 软换行。不过需要注意的是,它并不是在每个字符之后都 插入
function wbr (target) {
return String(target).replace(/(?:<[^>]+>)|(?:&#?[0-9a-z]{2,6};)|(.{1})/gi, '$&<wbr>').replace(/><wbr>/g, '>');
}
!> 注:IE仅6-7兼容此标签 https://caniuse.com/#search=wbr
format
轻量字符串模版
function format (str, object) {
var array = Array.prototype.slice.call(arguments, 1);
return str.replace(/\\?\#{([^{}]+)\}/gm, function(match, name) {
if (match.charAt(0) == '\\')
return match.slice(1);
var index = Number(name)
if (index >= 0)
return array[index];
if (object && object[name] !== void 0)
return object[name];
return '';
});
}
Example:
var a = format("Result is #{0},#{1}", 22, 33);
console.log(a); //"Result is 22,33"
var b = format("#{name} is a #{sex}", {
name: "Jhon",
sex: "man"
});
console.log(b); //"Jhon is a man"
quote
在字符串两端添加双引号,然后内部需要转义的地方都要转义,用于接装 JSON 的键名或模析系统中。
// 原生方法,需要浏览器支持原生JSON
JSON.stringify
//http://code.google.com/p/jquery-json/
var escapeable = /["\\\x00-\x1f\x7f-\x9f]/g,
meta = {
'\b': '\\b',
'\t': '\\t',
'\n': '\\n',
'\f': '\\f',
'\r': '\\r',
'"': '\\"',
'\\': '\\\\'
};
function quote (target) {
if (target.match(escapeable)) {
return '"' + target.replace(escapeable, function(a) {
var c = meta[a];
if (typeof c === 'string') {
return c;
}
return '\\u' + ('0000' + c.charCodeAt(0).toString(16)).slice(-4)
}) + '"';
}
return '"' + target + '"';
}
//https://github.com/ecomfe/etpl/blob/2.1.0/src/main.js#L207
function stringLiteralize (source) {
return '"' +
source
.replace(/\x5C/g, '\\\\')
.replace(/"/g, '\\"')
.replace(/\x0A/g, '\\n')
.replace(/\x09/g, '\\t')
.replace(/\x0D/g, '\\r') + '"';
}
Array
数组元素交换位置
/**
* 数组元素交换位置
* @param {array} arr 数组
* @param {number} index1 添加项目的位置
* @param {number} index2 删除项目的位置
* index1和index2分别是两个数组的索引值,即是两个要交换元素位置的索引值,如1,5就是数组中下标为1和5的两个元素交换位置
*/
function swapItem (arr, index1, index2) {
arr[index1] = arr.splice(index2, 1, arr[index1])[0];
return arr;
}
Object
get
用法同lodash的get
function get (object, path, defaultValue) {
return (!Array.isArray(path) ? path.replace(/\[/g, '.').replace(/\]/g, '').split('.') : path)
.reduce((obj, key) => (obj || {})[key], object) || defaultValue;
}
toQueryString
const toQueryString = obj => Object.keys(obj).map(key => `${encodeURIComponent(key)}=${encodeURIComponent(obj[key])}`).join('&');
Number
splitBit
千分位分割
function splitBit (num) {
var c = (num.toString().indexOf ('.') !== -1) ? num.toLocaleString() : num.toString().replace(/(\d)(?=(?:\d{3})+$)/g, '$1,');
return c;
}
Function
throttle
节流函数
应用场景:多数在监听页面元素滚动事件的时候会用到。因为滚动事件,是一个高频触发的事件。
function throttle (func, wait, options) {
var timeout = void 0,
context = void 0,
args = void 0,
result = void 0;
var previous = 0;
if (!options) options = {};
var later = function later() {
previous = options.leading === false ? 0 : Date.now();
timeout = null;
result = func.apply(context, args);
if (!timeout) context = args = null;
};
var throttled = function throttled() {
var now = Date.now();
if (!previous && options.leading === false) previous = now;
var remaining = wait - (now - previous);
context = this;
args = arguments;
if (remaining <= 0 || remaining > wait) {
if (timeout) {
clearTimeout(timeout);
timeout = null;
}
previous = now;
result = func.apply(context, args);
if (!timeout) context = args = null;
} else if (!timeout && options.trailing !== false) {
timeout = setTimeout(later, remaining);
}
return result;
};
throttled.cancel = function () {
clearTimeout(timeout);
previous = 0;
timeout = context = args = null;
};
return throttled;
}
debounce
防抖函数
应用场景:最常见的就是用户注册时候的手机号码验证和邮箱验证了。只有等用户输入完毕后,前端才需要检查格式是否正确,如果不正确,再弹出提示语。
function debounce (fn, context) {
fn.tId && clearTimeout(fn.tId)
fn.tId = setTimeout((() => {
fn.call(context)
}, 500)
}
function debounce(func, wait, immediate) {
var timeout = void 0;
return function () {
var context = this,
args = arguments;
var later = function later() {
timeout = null;
if (!immediate) {
func.apply(context, args);
}
};
var callNow = immediate && !timeout;
clearTimeout(timeout);
timeout = setTimeout(later, wait);
if (callNow) {
func.apply(context, args);
}
};
}
Lang
isType
function isType (value, type) {
return ({}).toString.call(value) === '[object ' + type + ']';
}
Dom
getStyle
function getStyle (dom, styleName) {
if (!dom || !styleName) return null;
styleName = camelize(styleName);
if (styleName === 'float') {
styleName = 'cssFloat';
}
/**
* let style = window.getComputedStyle(dom, null);
* 它等价于
* let style = document.defaultView.getComputedStyle(dom, null);
*/
return dom.currentStyle ? dom.currentStyle[styleName] : getComputedStyle(dom, null)[styleName]; // 火狐
}
getWidth
function getWidth (dom) {
let stl = root.currentStyle || document.defaultView.getComputedStyle(dom);
return ((dom.clientWidth || parseInt(stl.width, 10)) - parseInt(stl.paddingLeft, 10) - parseInt(stl.paddingRight, 10)).toFixed(0) - 0;
}
modifyCSS
function modifyCSS (dom, css) {
if (dom) {
for (var key in css) {
if (css.hasOwnProperty(key)) {
dom.style[key] = css[key];
}
}
}
return dom;
}
hasClass
function hasClass (el, cls) {
if (!el || !cls) {return false;}
if (cls.indexOf(' ') !== -1) {throw new Error('className should not contain space.');}
if (el.classList) {
return el.classList.contains(cls);
} else {
return (' ' + el.className + ' ').indexOf(' ' + cls + ' ') > -1;
}
}
removeClass
function removeClass (el, cls) {
if (!el || !cls) {return;}
const classes = cls.split(' ');
let curClass = ' ' + el.className + ' ';
for (let i = 0, j = classes.length; i < j; i++) {
const clsName = classes[i];
if (!clsName) {continue;}
if (el.classList) {
el.classList.remove(clsName);
} else {
if (hasClass(el, clsName)) {
curClass = curClass.replace(' ' + clsName + ' ', ' ');
}
}
}
if (!el.classList) {
el.className = trim(curClass);
}
}
addClass
/**
* Created by linqiang on 2019/6/5.
*/
function addClass (el, cls) {
if (!el) {return;}
let curClass = el.className;
const classes = (cls || '').split(' ');
for (let i = 0, j = classes.length; i < j; i++) {
const clsName = classes[i];
if (!clsName) {continue;}
if (el.classList) {
el.classList.add(clsName);
} else {
if (!hasClass(el, clsName)) {
curClass += ' ' + clsName;
}
}
}
if (!el.classList) {
el.className = curClass;
}
}
setOpacity
设置透明度
function setOpacity (elem, value) {
elem.filters ? elem.style.filter = 'alpha(opacity=' + value + ')' : elem.style.opacity = value / 100;
}
getScrollTop
获得当前视口距离页面顶部的像素
function getScrollTop () {
return document.documentElement.scrollTop || window.pageYOffset || document.body.scrollTop
}
getScrollLeft
获得当前视口距离页面左边的像素
function getScrollLeft () {
return document.documentElement.scrollLeft || window.pageXOffset || document.body.scrollLeft
}
addEventListener
/**
* 添加事件监听器
* @param {Object} target DOM对象
* @param {String} eventType 事件名
* @param {Funtion} callback 回调函数
* @return {Object} 返回对象
*/
function addEventListener (target, eventType, callback) {
if (target) {
if (target.addEventListener) {
target.addEventListener(eventType, callback, false);
return {
remove: function remove() {
target.removeEventListener(eventType, callback, false);
}
};
} else if (target.attachEvent) {
target.attachEvent('on' + eventType, callback);
return {
remove: function remove() {
target.detachEvent('on' + eventType, callback);
}
};
}
}
}
getKeyCode
document.onkeypress = function(e){
e = e || window.event;
console.log(e.keyCode || e.which); // 常规浏览器 || IE
}
stopProp
阻止事件冒泡
function stopProp (event) {
event = event || window.event;
event.stopPropagation ? event.stopPropagation() : event.cancelBubble = true; // 常规浏览器 || IE
};
preDef
阻止浏览器默认行为,如:按标签链接跳转
function preDef (event) {
event = event || window.event
event.preventDefault ? event.preventDefault() : event.returnValue = false // 常规浏览器 | IE
}
isIE6
IE6判定
function isIE6 () {
//在IE6中[-1,].toString()为“1,”,‘-’会进行类型转换(转成数字类型),-"1," 为NaN,所以返回!false
//非IE6 非IE6中[-1,].toString()为“1”,‘-’会进行类型转换(转成数字类型),-"1" 为-1,所以返回!true
return !-[1,];
}
判定IE浏览器
function isIE () {
//因为VB是微软发明的,其他浏览器无VBArray,至少可判定IE 6/7/8/9/10
return !!window.VBArray;
}