JavaScript 部分

1. type 类型判断使用

  1. function isString(o) { //是否字符串
  2. return Object.prototype.toString.call(o).slice(8, -1) === 'String'
  3. }
  4. function isNumber(o) { //是否数字
  5. return Object.prototype.toString.call(o).slice(8, -1) === 'Number'
  6. }
  7. function isBoolean(o) { //是否boolean
  8. return Object.prototype.toString.call(o).slice(8, -1) === 'Boolean'
  9. }
  10. function isFunction(o) { //是否函数
  11. return Object.prototype.toString.call(o).slice(8, -1) === 'Function'
  12. }
  13. function isNull(o) { //是否为null
  14. return Object.prototype.toString.call(o).slice(8, -1) === 'Null'
  15. }
  16. function isUndefined(o) { //是否undefined
  17. return Object.prototype.toString.call(o).slice(8, -1) === 'Undefined'
  18. }
  19. function isObj(o) { //是否对象
  20. return Object.prototype.toString.call(o).slice(8, -1) === 'Object'
  21. }
  22. function isArray(o) { //是否数组
  23. return Object.prototype.toString.call(o).slice(8, -1) === 'Array'
  24. }
  25. function isDate(o) { //是否时间
  26. return Object.prototype.toString.call(o).slice(8, -1) === 'Date'
  27. }
  28. function isRegExp(o) { //是否正则
  29. return Object.prototype.toString.call(o).slice(8, -1) === 'RegExp'
  30. }
  31. function isError(o) { //是否错误对象
  32. return Object.prototype.toString.call(o).slice(8, -1) === 'Error'
  33. }
  34. function isSymbol(o) { //是否Symbol函数
  35. return Object.prototype.toString.call(o).slice(8, -1) === 'Symbol'
  36. }
  37. function isPromise(o) { //是否Promise对象
  38. return Object.prototype.toString.call(o).slice(8, -1) === 'Promise'
  39. }
  40. function isSet(o) { //是否Set对象
  41. return Object.prototype.toString.call(o).slice(8, -1) === 'Set'
  42. }
  43. function isFalse(o) {
  44. if (!o || o === 'null' || o === 'undefined' || o === 'false' || o === 'NaN') return true
  45. return false
  46. }
  47. function isTrue(o) {
  48. return !this.isFalse(o)
  49. }
  50. function isIos() {
  51. var u = navigator.userAgent;
  52. if (u.indexOf('Android') > -1 || u.indexOf('Linux') > -1) { //安卓手机
  53. // return "Android";
  54. return false
  55. } else if (u.indexOf('iPhone') > -1) { //苹果手机
  56. // return "iPhone";
  57. return true
  58. } else if (u.indexOf('iPad') > -1) { //iPad
  59. // return "iPad";
  60. return false
  61. } else if (u.indexOf('Windows Phone') > -1) { //winphone手机
  62. // return "Windows Phone";
  63. return false
  64. } else {
  65. return false
  66. }
  67. }
  68. function isPC() { //是否为PC端
  69. var userAgentInfo = navigator.userAgent;
  70. var Agents = ["Android", "iPhone",
  71. "SymbianOS", "Windows Phone",
  72. "iPad", "iPod"
  73. ];
  74. var flag = true;
  75. for (var v = 0; v < Agents.length; v++) {
  76. if (userAgentInfo.indexOf(Agents[v]) > 0) {
  77. flag = false;
  78. break;
  79. }
  80. }
  81. return flag;
  82. }
  83. function browserType() {
  84. var userAgent = navigator.userAgent; //取得浏览器的userAgent字符串
  85. var isOpera = userAgent.indexOf("Opera") > -1; //判断是否Opera浏览器
  86. var isIE = userAgent.indexOf("compatible") > -1 && userAgent.indexOf("MSIE") > -1 && !isOpera; //判断是否IE浏览器
  87. var isIE11 = userAgent.indexOf('Trident') > -1 && userAgent.indexOf("rv:11.0") > -1;
  88. var isEdge = userAgent.indexOf("Edge") > -1 && !isIE; //判断是否IE的Edge浏览器
  89. var isFF = userAgent.indexOf("Firefox") > -1; //判断是否Firefox浏览器
  90. var isSafari = userAgent.indexOf("Safari") > -1 && userAgent.indexOf("Chrome") == -1; //判断是否Safari浏览器
  91. var isChrome = userAgent.indexOf("Chrome") > -1 && userAgent.indexOf("Safari") > -1; //判断Chrome浏览器
  92. if (isIE) {
  93. var reIE = new RegExp("MSIE (\\d+\\.\\d+);");
  94. reIE.test(userAgent);
  95. var fIEVersion = parseFloat(RegExp["$1"]);
  96. if (fIEVersion == 7) return "IE7"
  97. else if (fIEVersion == 8) return "IE8";
  98. else if (fIEVersion == 9) return "IE9";
  99. else if (fIEVersion == 10) return "IE10";
  100. else return "IE7以下" //IE版本过低
  101. }
  102. if (isIE11) return 'IE11';
  103. if (isEdge) return "Edge";
  104. if (isFF) return "FF";
  105. if (isOpera) return "Opera";
  106. if (isSafari) return "Safari";
  107. if (isChrome) return "Chrome";
  108. }
  109. // 常用正则表达式验证
  110. function checkStr(str, type) {
  111. switch (type) {
  112. case 'phone': //手机号码
  113. return /^1[3|4|5|6|7|8|9][0-9]{9}$/.test(str);
  114. case 'tel': //座机
  115. return /^(0\d{2,3}-\d{7,8})(-\d{1,4})?$/.test(str);
  116. case 'card': //身份证
  117. return /(^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x)$)/.test(str);
  118. case 'pwd': //密码以字母开头,长度在6~18之间,只能包含字母、数字和下划线
  119. return /^[a-zA-Z]\w{5,17}$/.test(str)
  120. case 'postal': //邮政编码
  121. return /[1-9]\d{5}(?!\d)/.test(str);
  122. case 'QQ': //QQ号
  123. return /^[1-9][0-9]{4,9}$/.test(str);
  124. case 'email': //邮箱
  125. return /^[\w-]+(\.[\w-]+)*@[\w-]+(\.[\w-]+)+$/.test(str);
  126. case 'money': //金额(小数点2位)
  127. return /^\d*(?:\.\d{0,2})?$/.test(str);
  128. case 'URL': //网址
  129. return /(http|ftp|https):\/\/[\w\-_]+(\.[\w\-_]+)+([\w\-\.,@?^=%&:/~\+#]*[\w\-\@?^=%&/~\+#])?/.test(str)
  130. case 'IP': //IP
  131. return /((?:(?:25[0-5]|2[0-4]\\d|[01]?\\d?\\d)\\.){3}(?:25[0-5]|2[0-4]\\d|[01]?\\d?\\d))/.test(str);
  132. case 'date': //日期时间
  133. return /^(\d{4})\-(\d{2})\-(\d{2}) (\d{2})(?:\:\d{2}|:(\d{2}):(\d{2}))$/.test(str) || /^(\d{4})\-(\d{2})\-(\d{2})$/.test(str)
  134. case 'number': //数字
  135. return /^[0-9]$/.test(str);
  136. case 'english': //英文
  137. return /^[a-zA-Z]+$/.test(str);
  138. case 'chinese': //中文
  139. return /^[\u4E00-\u9FA5]+$/.test(str);
  140. case 'lower': //小写
  141. return /^[a-z]+$/.test(str);
  142. case 'upper': //大写
  143. return /^[A-Z]+$/.test(str);
  144. case 'HTML': //HTML标记
  145. return /<("[^"]*"|'[^']*'|[^'">])*>/.test(str);
  146. default:
  147. return true;
  148. }
  149. // 严格的身份证校验
  150. function isCardID(sId) {
  151. if (!/(^\d{15}$)|(^\d{17}(\d|X|x)$)/.test(sId)) {
  152. alert('你输入的身份证长度或格式错误')
  153. return false
  154. }
  155. //身份证城市
  156. var aCity = {
  157. 11: "北京",
  158. 12: "天津",
  159. 13: "河北",
  160. 14: "山西",
  161. 15: "内蒙古",
  162. 21: "辽宁",
  163. 22: "吉林",
  164. 23: "黑龙江",
  165. 31: "上海",
  166. 32: "江苏",
  167. 33: "浙江",
  168. 34: "安徽",
  169. 35: "福建",
  170. 36: "江西",
  171. 37: "山东",
  172. 41: "河南",
  173. 42: "湖北",
  174. 43: "湖南",
  175. 44: "广东",
  176. 45: "广西",
  177. 46: "海南",
  178. 50: "重庆",
  179. 51: "四川",
  180. 52: "贵州",
  181. 53: "云南",
  182. 54: "西藏",
  183. 61: "陕西",
  184. 62: "甘肃",
  185. 63: "青海",
  186. 64: "宁夏",
  187. 65: "新疆",
  188. 71: "台湾",
  189. 81: "香港",
  190. 82: "澳门",
  191. 91: "国外"
  192. };
  193. if (!aCity[parseInt(sId.substr(0, 2))]) {
  194. alert('你的身份证地区非法')
  195. return false
  196. }
  197. // 出生日期验证
  198. var sBirthday = (sId.substr(6, 4) + "-" + Number(sId.substr(10, 2)) + "-" + Number(sId.substr(12, 2))).replace(/-/g, "/"),
  199. d = new Date(sBirthday)
  200. if (sBirthday != (d.getFullYear() + "/" + (d.getMonth() + 1) + "/" + d.getDate())) {
  201. alert('身份证上的出生日期非法')
  202. return false
  203. }
  204. // 身份证号码校验
  205. var sum = 0,
  206. weights = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2],
  207. codes = "10X98765432"
  208. for (var i = 0; i < sId.length - 1; i++) {
  209. sum += sId[i] * weights[i];
  210. }
  211. var last = codes[sum % 11]; //计算出来的最后一位身份证号码
  212. if (sId[sId.length - 1] != last) {
  213. alert('你输入的身份证号非法')
  214. return false
  215. }
  216. return true
  217. }
  218. }

2. Date 日期操作总结

/**
 * 格式化时间
 *
 * @param  {time} 时间
 * @param  {cFormat} 格式
 * @return {String} 字符串
 *
 * @example formatTime('2018-1-29', '{y}/{m}/{d} {h}:{i}:{s}') // -> 2018/01/29 00:00:00
 */
function formatTime(time, cFormat) {
  if (arguments.length === 0) return null
  if ((time + '').length === 10) {
    time = +time * 1000
  }

  var format = cFormat || '{y}-{m}-{d} {h}:{i}:{s}',
    date
  if (typeof time === 'object') {
    date = time
  } else {
    date = new Date(time)
  }

  var formatObj = {
    y: date.getFullYear(),
    m: date.getMonth() + 1,
    d: date.getDate(),
    h: date.getHours(),
    i: date.getMinutes(),
    s: date.getSeconds(),
    a: date.getDay()
  }
  var time_str = format.replace(/{(y|m|d|h|i|s|a)+}/g, (result, key) => {
    var value = formatObj[key]
    if (key === 'a') return ['一', '二', '三', '四', '五', '六', '日'][value - 1]
    if (result.length > 0 && value < 10) {
      value = '0' + value
    }
    return value || 0
  })
  return time_str
}

/**
 * 返回指定长度的月份集合
 *
 * @param  {time} 时间
 * @param  {len} 长度
 * @param  {direction} 方向:  1: 前几个月;  2: 后几个月;  3:前后几个月  默认 3
 * @return {Array} 数组
 *
 * @example   getMonths('2018-1-29', 6, 1)  // ->  ["2018-1", "2017-12", "2017-11", "2017-10", "2017-9", "2017-8", "2017-7"]
 */
function getMonths(time, len, direction) {
  var mm = new Date(time).getMonth(),
    yy = new Date(time).getFullYear(),
    direction = isNaN(direction) ? 3 : direction,
    index = mm;
  var cutMonth = function (index) {
    if (index <= len && index >= -len) {
      return direction === 1 ? formatPre(index).concat(cutMonth(++index)) :
        direction === 2 ? formatNext(index).concat(cutMonth(++index)) : formatCurr(index).concat(cutMonth(++index))
    }
    return []
  }
  var formatNext = function (i) {
    var y = Math.floor(i / 12),
      m = i % 12
    return [yy + y + '-' + (m + 1)]
  }
  var formatPre = function (i) {
    var y = Math.ceil(i / 12),
      m = i % 12
    m = m === 0 ? 12 : m
    return [yy - y + '-' + (13 - m)]
  }
  var formatCurr = function (i) {
    var y = Math.floor(i / 12),
      yNext = Math.ceil(i / 12),
      m = i % 12,
      mNext = m === 0 ? 12 : m
    return [yy - yNext + '-' + (13 - mNext), yy + y + '-' + (m + 1)]
  }
  // 数组去重
  var unique = function (arr) {
    if (Array.hasOwnProperty('from')) {
      return Array.from(new Set(arr));
    } else {
      var n = {},
        r = [];
      for (var i = 0; i < arr.length; i++) {
        if (!n[arr[i]]) {
          n[arr[i]] = true;
          r.push(arr[i]);
        }
      }
      return r;
    }
  }
  return direction !== 3 ? cutMonth(index) : unique(cutMonth(index).sort(function (t1, t2) {
    return new Date(t1).getTime() - new Date(t2).getTime()
  }))
}

/**
 * 返回指定长度的天数集合
 *
 * @param  {time} 时间
 * @param  {len} 长度
 * @param  {direction} 方向: 1: 前几天;  2: 后几天;  3:前后几天  默认 3
 * @return {Array} 数组
 *
 * @example date.getDays('2018-1-29', 6) // -> ["2018-1-26", "2018-1-27", "2018-1-28", "2018-1-29", "2018-1-30", "2018-1-31", "2018-2-1"]
 */
function getDays(time, len, diretion) {
  var tt = new Date(time)
  var getDay = function (day) {
    var t = new Date(time)
    t.setDate(t.getDate() + day)
    var m = t.getMonth() + 1
    return t.getFullYear() + '-' + m + '-' + t.getDate()
  }
  var arr = []
  if (diretion === 1) {
    for (var i = 1; i <= len; i++) {
      arr.unshift(getDay(-i))
    }
  } else if (diretion === 2) {
    for (var i = 1; i <= len; i++) {
      arr.push(getDay(i))
    }
  } else {
    for (var i = 1; i <= len; i++) {
      arr.unshift(getDay(-i))
    }
    arr.push(tt.getFullYear() + '-' + (tt.getMonth() + 1) + '-' + tt.getDate())
    for (var i = 1; i <= len; i++) {
      arr.push(getDay(i))
    }
  }
  return diretion === 1 ? arr.concat([tt.getFullYear() + '-' + (tt.getMonth() + 1) + '-' + tt.getDate()]) :
    diretion === 2 ? [tt.getFullYear() + '-' + (tt.getMonth() + 1) + '-' + tt.getDate()].concat(arr) : arr
}

/**
 * @param  {s} 秒数
 * @return {String} 字符串
 *
 * @example formatHMS(3610) // -> 1h0m10s
 */
function formatHMS(s) {
  var str = ''
  if (s > 3600) {
    str = Math.floor(s / 3600) + 'h' + Math.floor(s % 3600 / 60) + 'm' + s % 60 + 's'
  } else if (s > 60) {
    str = Math.floor(s / 60) + 'm' + s % 60 + 's'
  } else {
    str = s % 60 + 's'
  }
  return str
}

/*获取某月有多少天*/
getMonthOfDay(time) {
  var date = new Date(time)
  var year = date.getFullYear()
  var mouth = date.getMonth() + 1
  var days

  //当月份为二月时,根据闰年还是非闰年判断天数
  if (mouth == 2) {
    days = (year % 4 == 0 && year % 100 == 0 && year % 400 == 0) || (year % 4 == 0 && year % 100 != 0) ? 28 : 29
  } else if (mouth == 1 || mouth == 3 || mouth == 5 || mouth == 7 || mouth == 8 || mouth == 10 || mouth == 12) {
    //月份为:1,3,5,7,8,10,12 时,为大月.则天数为31;
    days = 31
  } else {
    //其他月份,天数为:30.
    days = 30
  }
  return days
}

/*获取某年有多少天*/
function getYearOfDay(time) {
  var firstDayYear = this.getFirstDayOfYear(time);
  var lastDayYear = this.getLastDayOfYear(time);
  var numSecond = (new Date(lastDayYear).getTime() - new Date(firstDayYear).getTime()) / 1000;
  return Math.ceil(numSecond / (24 * 3600));
}

/*获取某年的第一天*/
function getFirstDayOfYear(time) {
  var year = new Date(time).getFullYear();
  return year + "-01-01 00:00:00";
}

/*获取某年最后一天*/
function getLastDayOfYear(time) {
  var year = new Date(time).getFullYear();
  var dateString = year + "-12-01 00:00:00";
  var endDay = this.getMonthOfDay(dateString);
  return year + "-12-" + endDay + " 23:59:59";
}

/*获取某个日期是当年中的第几天*/
function getDayOfYear(time) {
  var firstDayYear = this.getFirstDayOfYear(time);
  var numSecond = (new Date(time).getTime() - new Date(firstDayYear).getTime()) / 1000;
  return Math.ceil(numSecond / (24 * 3600));
}

/*获取某个日期在这一年的第几周*/
function getDayOfYearWeek(time) {
  var numdays = this.getDayOfYear(time);
  return Math.ceil(numdays / 7);
}

3. Array操作总结

/*判断一个元素是否在数组中*/
function contains(arr, val) {
  return arr.indexOf(val) != -1 ? true : false;
}

/**
 * @param  {arr} 数组
 * @param  {fn} 回调函数
 * @return {undefined}
 */
function each(arr, fn) {
  fn = fn || Function;
  var a = [];
  var args = Array.prototype.slice.call(arguments, 1);
  for (var i = 0; i < arr.length; i++) {
    var res = fn.apply(arr, [arr[i], i].concat(args));
    if (res != null) a.push(res);
  }
}

/**
 * @param  {arr} 数组
 * @param  {fn} 回调函数
 * @param  {thisObj} this指向
 * @return {Array} 
 */
function map(arr, fn, thisObj) {
  var scope = thisObj || window;
  var a = [];
  for (var i = 0, j = arr.length; i < j; ++i) {
    var res = fn.call(scope, arr[i], i, this);
    if (res != null) a.push(res);
  }
  return a;
}

/**
 * @param  {arr} 数组
 * @param  {type} 1:从小到大   2:从大到小   3:随机
 * @return {Array}
 */
function sort(arr, type = 1) {
  return arr.sort((a, b) => {
    switch (type) {
      case 1:
        return a - b;
      case 2:
        return b - a;
      case 3:
        return Math.random() - 0.5;
      default:
        return arr;
    }
  })
}

/*去重*/
function unique(arr) {
  if (Array.hasOwnProperty('from')) {
    return Array.from(new Set(arr));
  } else {
    var n = {},
      r = [];
    for (var i = 0; i < arr.length; i++) {
      if (!n[arr[i]]) {
        n[arr[i]] = true;
        r.push(arr[i]);
      }
    }
    return r;
  }
  // 注:上面 else 里面的排重并不能区分 2 和 '2',但能减少用indexOf带来的性能,暂时没找到替代的方法。。。
  /* 正确排重
  if ( Array.hasOwnProperty('from') ) {
      return Array.from(new Set(arr))
  }else{
      var r = [], NaNBol = true
      for(var i=0; i < arr.length; i++) {
          if (arr[i] !== arr[i]) {
              if (NaNBol && r.indexOf(arr[i]) === -1) {
                  r.push(arr[i])
                  NaNBol = false
              }
          }else{
              if(r.indexOf(arr[i]) === -1) r.push(arr[i])
          }
      }
      return r
  }

   */
}

/*求两个集合的并集*/
function union(a, b) {
  var newArr = a.concat(b);
  return this.unique(newArr);
}

/*求两个集合的交集*/
function intersect(a, b) {
  var _this = this;
  a = this.unique(a);
  return this.map(a, function (o) {
    return _this.contains(b, o) ? o : null;
  });
}

/*删除其中一个元素*/
function remove(arr, ele) {
  var index = arr.indexOf(ele);
  if (index > -1) {
    arr.splice(index, 1);
  }
  return arr;
}

/*将类数组转换为数组的方法*/
function formArray(ary) {
  var arr = [];
  if (Array.isArray(ary)) {
    arr = ary;
  } else {
    arr = Array.prototype.slice.call(ary);
  };
  return arr;
}

/*最大值*/
function max(arr) {
  return Math.max.apply(null, arr);
}

/*最小值*/
function min(arr) {
  return Math.min.apply(null, arr);
}

/*求和*/
function sum(arr) {
  return arr.reduce((pre, cur) => {
    return pre + cur
  })
}

/*平均值*/
function average(arr) {
  return this.sum(arr) / arr.length
}

4. String 字符串操作实战

/**
 * 去除空格
 * @param  {str}
 * @param  {type} 
 * type:  1-所有空格  2-前后空格  3-前空格 4-后空格
 * @return {String}
 */
function trim(str, type) {
  type = type || 1
  switch (type) {
    case 1:
      return str.replace(/\s+/g, "");
    case 2:
      return str.replace(/(^\s*)|(\s*$)/g, "");
    case 3:
      return str.replace(/(^\s*)/g, "");
    case 4:
      return str.replace(/(\s*$)/g, "");
    default:
      return str;
  }
}

/**
 * @param  {str} 
 * @param  {type}
 *       type:  1:首字母大写  2:首页母小写  3:大小写转换  4:全部大写  5:全部小写
 * @return {String}
 */
function changeCase(str, type) {
  type = type || 4
  switch (type) {
    case 1:
      return str.replace(/\b\w+\b/g, function (word) {
        return word.substring(0, 1).toUpperCase() + word.substring(1).toLowerCase();

      });
    case 2:
      return str.replace(/\b\w+\b/g, function (word) {
        return word.substring(0, 1).toLowerCase() + word.substring(1).toUpperCase();
      });
    case 3:
      return str.split('').map(function (word) {
        if (/[a-z]/.test(word)) {
          return word.toUpperCase();
        } else {
          return word.toLowerCase()
        }
      }).join('')
    case 4:
      return str.toUpperCase();
    case 5:
      return str.toLowerCase();
    default:
      return str;
  }
}

/*
 * 检测密码强度
 */
function checkPwd(str) {
  var Lv = 0;
  if (str.length < 6) {
    return Lv
  }
  if (/[0-9]/.test(str)) {
    Lv++
  }
  if (/[a-z]/.test(str)) {
    Lv++
  }
  if (/[A-Z]/.test(str)) {
    Lv++
  }
  if (/[\.|-|_]/.test(str)) {
    Lv++
  }
  return Lv;
}

/*过滤html代码(把<>转换)*/
function filterTag(str) {
  str = str.replace(/&/ig, "&amp;");
  str = str.replace(/</ig, "&lt;");
  str = str.replace(/>/ig, "&gt;");
  str = str.replace(" ", " ");
  return str;
}

5. Number 操作实战


/*随机数范围*/
function random(min, max) {
  if (arguments.length === 2) {
    return Math.floor(min + Math.random() * ((max + 1) - min))
  } else {
    return null;
  }
}

/*将阿拉伯数字翻译成中文的大写数字*/
function numberToChinese(num) {
  var AA = new Array("零", "一", "二", "三", "四", "五", "六", "七", "八", "九", "十");
  var BB = new Array("", "十", "百", "仟", "萬", "億", "点", "");
  var a = ("" + num).replace(/(^0*)/g, "").split("."),
    k = 0,
    re = "";
  for (var i = a[0].length - 1; i >= 0; i--) {
    switch (k) {
      case 0:
        re = BB[7] + re;
        break;
      case 4:
        if (!new RegExp("0{4}//d{" + (a[0].length - i - 1) + "}$")
          .test(a[0]))
          re = BB[4] + re;
        break;
      case 8:
        re = BB[5] + re;
        BB[7] = BB[5];
        k = 0;
        break;
    }
    if (k % 4 == 2 && a[0].charAt(i + 2) != 0 && a[0].charAt(i + 1) == 0)
      re = AA[0] + re;
    if (a[0].charAt(i) != 0)
      re = AA[a[0].charAt(i)] + BB[k % 4] + re;
    k++;
  }

  if (a.length > 1) // 加上小数部分(如果有小数部分)
  {
    re += BB[6];
    for (var i = 0; i < a[1].length; i++)
      re += AA[a[1].charAt(i)];
  }
  if (re == '一十')
    re = "十";
  if (re.match(/^一/) && re.length == 3)
    re = re.replace("一", "");
  return re;
}

/*将数字转换为大写金额*/
function changeToChinese(Num) {
  //判断如果传递进来的不是字符的话转换为字符
  if (typeof Num == "number") {
    Num = new String(Num);
  };
  Num = Num.replace(/,/g, "") //替换tomoney()中的“,”
  Num = Num.replace(/ /g, "") //替换tomoney()中的空格
  Num = Num.replace(/¥/g, "") //替换掉可能出现的¥字符
  if (isNaN(Num)) { //验证输入的字符是否为数字
    //alert("请检查小写金额是否正确");
    return "";
  };
  //字符处理完毕后开始转换,采用前后两部分分别转换
  var part = String(Num).split(".");
  var newchar = "";
  //小数点前进行转化
  for (var i = part[0].length - 1; i >= 0; i--) {
    if (part[0].length > 10) {
      return "";
      //若数量超过拾亿单位,提示
    }
    var tmpnewchar = ""
    var perchar = part[0].charAt(i);
    switch (perchar) {
      case "0":
        tmpnewchar = "零" + tmpnewchar;
        break;
      case "1":
        tmpnewchar = "壹" + tmpnewchar;
        break;
      case "2":
        tmpnewchar = "贰" + tmpnewchar;
        break;
      case "3":
        tmpnewchar = "叁" + tmpnewchar;
        break;
      case "4":
        tmpnewchar = "肆" + tmpnewchar;
        break;
      case "5":
        tmpnewchar = "伍" + tmpnewchar;
        break;
      case "6":
        tmpnewchar = "陆" + tmpnewchar;
        break;
      case "7":
        tmpnewchar = "柒" + tmpnewchar;
        break;
      case "8":
        tmpnewchar = "捌" + tmpnewchar;
        break;
      case "9":
        tmpnewchar = "玖" + tmpnewchar;
        break;
    }
    switch (part[0].length - i - 1) {
      case 0:
        tmpnewchar = tmpnewchar + "元";
        break;
      case 1:
        if (perchar != 0) tmpnewchar = tmpnewchar + "拾";
        break;
      case 2:
        if (perchar != 0) tmpnewchar = tmpnewchar + "佰";
        break;
      case 3:
        if (perchar != 0) tmpnewchar = tmpnewchar + "仟";
        break;
      case 4:
        tmpnewchar = tmpnewchar + "万";
        break;
      case 5:
        if (perchar != 0) tmpnewchar = tmpnewchar + "拾";
        break;
      case 6:
        if (perchar != 0) tmpnewchar = tmpnewchar + "佰";
        break;
      case 7:
        if (perchar != 0) tmpnewchar = tmpnewchar + "仟";
        break;
      case 8:
        tmpnewchar = tmpnewchar + "亿";
        break;
      case 9:
        tmpnewchar = tmpnewchar + "拾";
        break;
    }
    var newchar = tmpnewchar + newchar;
  }
  //小数点之后进行转化
  if (Num.indexOf(".") != -1) {
    if (part[1].length > 2) {
      // alert("小数点之后只能保留两位,系统将自动截断");
      part[1] = part[1].substr(0, 2)
    }
    for (i = 0; i < part[1].length; i++) {
      tmpnewchar = ""
      perchar = part[1].charAt(i)
      switch (perchar) {
        case "0":
          tmpnewchar = "零" + tmpnewchar;
          break;
        case "1":
          tmpnewchar = "壹" + tmpnewchar;
          break;
        case "2":
          tmpnewchar = "贰" + tmpnewchar;
          break;
        case "3":
          tmpnewchar = "叁" + tmpnewchar;
          break;
        case "4":
          tmpnewchar = "肆" + tmpnewchar;
          break;
        case "5":
          tmpnewchar = "伍" + tmpnewchar;
          break;
        case "6":
          tmpnewchar = "陆" + tmpnewchar;
          break;
        case "7":
          tmpnewchar = "柒" + tmpnewchar;
          break;
        case "8":
          tmpnewchar = "捌" + tmpnewchar;
          break;
        case "9":
          tmpnewchar = "玖" + tmpnewchar;
          break;
      }
      if (i == 0) tmpnewchar = tmpnewchar + "角";
      if (i == 1) tmpnewchar = tmpnewchar + "分";
      newchar = newchar + tmpnewchar;
    }
  }
  //替换所有无用汉字
  while (newchar.search("零零") != -1)
    newchar = newchar.replace("零零", "零");
  newchar = newchar.replace("零亿", "亿");
  newchar = newchar.replace("亿万", "亿");
  newchar = newchar.replace("零万", "万");
  newchar = newchar.replace("零元", "元");
  newchar = newchar.replace("零角", "");
  newchar = newchar.replace("零分", "");
  if (newchar.charAt(newchar.length - 1) == "元") {
    newchar = newchar + "整"
  }
  return newchar;
}

6. Ajax、fetch

/**
 * @param  {setting}
 */
ajax(setting){
    //设置参数的初始值
    var opts={
        method: (setting.method || "GET").toUpperCase(), //请求方式
        url: setting.url || "", // 请求地址
        async: setting.async || true, // 是否异步
        dataType: setting.dataType || "json", // 解析方式
        data: setting.data || "", // 参数
        success: setting.success || function(){}, // 请求成功回调
        error: setting.error || function(){} // 请求失败回调
    }

    // 参数格式化
    function params_format (obj) {
        var str = ''
        for (var i in obj) {
            str += i + '=' + obj[i] + '&'
        }
        return str.split('').slice(0, -1).join('')
    }

    // 创建ajax对象
    var xhr=new XMLHttpRequest();

    // 连接服务器open(方法GET/POST,请求地址, 异步传输)
    if(opts.method == 'GET'){
        xhr.open(opts.method, opts.url + "?" + params_format(opts.data), opts.async);
        xhr.send();
    }else{
        xhr.open(opts.method, opts.url, opts.async);
        xhr.setRequestHeader("Content-Type","application/x-www-form-urlencoded");
        xhr.send(opts.data);
    }

    /*
    ** 每当readyState改变时,就会触发onreadystatechange事件
    ** readyState属性存储有XMLHttpRequest的状态信息
    ** 0 :请求未初始化
    ** 1 :服务器连接已建立
    ** 2 :请求已接受
    ** 3 : 请求处理中
    ** 4 :请求已完成,且相应就绪
    */
    xhr.onreadystatechange = function() {
        if (xhr.readyState === 4 && (xhr.status === 200 || xhr.status === 304)) {
            switch(opts.dataType){
                case "json":
                    var json = JSON.parse(xhr.responseText);
                    opts.success(json);
                    break;
                case "xml":
                    opts.success(xhr.responseXML);
                    break;
                default:
                    opts.success(xhr.responseText);
                    break;
            }
        }
    }

    xhr.onerror = function(err) {
        opts.error(err);
    }
}

/**
 * @param  {url}
 * @param  {setting}
 * @return {Promise}
 */
fetch(url, setting) {
    //设置参数的初始值
    let opts={
        method: (setting.method || 'GET').toUpperCase(), //请求方式
        headers : setting.headers  || {}, // 请求头设置
        credentials : setting.credentials  || true, // 设置cookie是否一起发送
        body: setting.body || {},
        mode : setting.mode  || 'no-cors', // 可以设置 cors, no-cors, same-origin
        redirect : setting.redirect  || 'follow', // follow, error, manual
        cache : setting.cache  || 'default' // 设置 cache 模式 (default, reload, no-cache)
    }
    let dataType = setting.dataType || "json", // 解析方式  
        data = setting.data || "" // 参数

    // 参数格式化
    function params_format (obj) {
        var str = ''
        for (var i in obj) {
            str += `${i}=${obj[i]}&`
        }
        return str.split('').slice(0, -1).join('')
    }

    if (opts.method === 'GET') {
        url = url + (data?`?${params_format(data)}`:'')
    }else{
        setting.body = data || {}
    }

    return new Promise( (resolve, reject) => {
        fetch(url, opts).then( async res => {
            let data = dataType === 'text' ? await res.text() :
                dataType === 'blob' ? await res.blob() : await res.json() 
            resolve(data)
        }).catch( e => {
            reject(e)
        })
    })
}

7. DOM 增删改查样式

$ (selector){ 
    var type = selector.substring(0, 1);
    if (type === '#') {
        if (document.querySelecotor) return document.querySelector(selector)
            return document.getElementById(selector.substring(1))

    }else if (type === '.') {
        if (document.querySelecotorAll) return document.querySelectorAll(selector)
            return document.getElementsByClassName(selector.substring(1))
    }else{
        return document['querySelectorAll' ? 'querySelectorAll':'getElementsByTagName'](selector)
    }
} 

/*检测类名*/
hasClass (ele, name) {
    return ele.className.match(new RegExp('(\\s|^)' + name + '(\\s|$)'));
}

/*添加类名*/
addClass (ele, name) {
    if (!this.hasClass(ele, name)) ele.className += " " + name;
}

/*删除类名*/
removeClass (ele, name) {
    if (this.hasClass(ele, name)) {
        var reg = new RegExp('(\\s|^)' + name + '(\\s|$)');
        ele.className = ele.className.replace(reg, '');
    }
}

/*替换类名*/
replaceClass (ele, newName, oldName) {
    this.removeClass(ele, oldName);
    this.addClass(ele, newName);
}

/*获取兄弟节点*/
siblings (ele) {
    console.log(ele.parentNode)
    var chid = ele.parentNode.children,eleMatch = []; 
    for(var i = 0, len = chid.length; i < len; i ++){ 
        if(chid[i] != ele){ 
            eleMatch.push(chid[i]); 
        } 
    } 
    return eleMatch;
}

/*获取行间样式属性*/
getByStyle (obj,name){
    if(obj.currentStyle){
        return  obj.currentStyle[name];
    }else{
        return  getComputedStyle(obj,false)[name];
    }
}

8. Storage 储存操作

class StorageFn {
    constructor () {
        this.ls = window.localStorage;
        this.ss = window.sessionStorage;
    }

    /*-----------------cookie---------------------*/
    /*设置cookie*/
    setCookie (name, value, day) {
        var setting = arguments[0];
        if (Object.prototype.toString.call(setting).slice(8, -1) === 'Object'){
            for (var i in setting) {
                var oDate = new Date();
                oDate.setDate(oDate.getDate() + day);
                document.cookie = i + '=' + setting[i] + ';expires=' + oDate;
            }
        }else{
            var oDate = new Date();
            oDate.setDate(oDate.getDate() + day);
            document.cookie = name + '=' + value + ';expires=' + oDate;
        }

    }

    /*获取cookie*/
    getCookie (name) {
        var arr = document.cookie.split('; ');
        for (var i = 0; i < arr.length; i++) {
            var arr2 = arr[i].split('=');
            if (arr2[0] == name) {
                return arr2[1];
            }
        }
        return '';
    }

    /*删除cookie*/
    removeCookie (name) {
        this.setCookie(name, 1, -1);
    }

    /*-----------------localStorage---------------------*/
    /*设置localStorage*/
    setLocal(key, val) {
        var setting = arguments[0];
        if (Object.prototype.toString.call(setting).slice(8, -1) === 'Object'){
            for(var i in setting){
                this.ls.setItem(i, JSON.stringify(setting[i]))
            }
        }else{
            this.ls.setItem(key, JSON.stringify(val))
        }

    }

    /*获取localStorage*/
    getLocal(key) {
        if (key) return JSON.parse(this.ls.getItem(key))
        return null;

    }

    /*移除localStorage*/
    removeLocal(key) {
        this.ls.removeItem(key)
    }

    /*移除所有localStorage*/
    clearLocal() {
        this.ls.clear()
    }

    /*-----------------sessionStorage---------------------*/
    /*设置sessionStorage*/
    setSession(key, val) {
        var setting = arguments[0];
        if (Object.prototype.toString.call(setting).slice(8, -1) === 'Object'){
            for(var i in setting){
                this.ss.setItem(i, JSON.stringify(setting[i]))
            }
        }else{
            this.ss.setItem(key, JSON.stringify(val))
        }

    }

    /*获取sessionStorage*/
    getSession(key) {
        if (key) return JSON.parse(this.ss.getItem(key))
        return null;

    }

    /*移除sessionStorage*/
    removeSession(key) {
        this.ss.removeItem(key)
    }

    /*移除所有sessionStorage*/
    clearSession() {
        this.ss.clear()
    }

}

9. URL地址转成对象格式

/**
 * @description: URL地址转成对象格式  https://www.baidu.com?name=张三&age=24&sex=男  =>   {name: "张三", age: "24", sex: "男"}
 * @param {string}  https://www.baidu.com?name=张三&age=24&sex=男
 * @return {object}  {name: "郝晨光", age: "24", sex: "男"}
 */
export function getURLParams(url) {
    let paramsStr = url.split('?')[1];
    let paramsArr = paramsStr.split('&');
    let result = {};
    for (let i = 0; i < paramsArr.length; i++) {
        let params = paramsArr[i].split('=');
        result[params[0]] = params[1];
    }
    return result;
}

/*获取全部url参数,并转换成json对象*/
export function getUrlAllParams (url) {
    var url = url ? url : window.location.href;
    var _pa = url.substring(url.indexOf('?') + 1),
        _arrS = _pa.split('&'),
        _rs = {};
    for (var i = 0, _len = _arrS.length; i < _len; i++) {
        var pos = _arrS[i].indexOf('=');
        if (pos == -1) {
            continue;
        }
        var name = _arrS[i].substring(0, pos),
            value = window.decodeURIComponent(_arrS[i].substring(pos + 1));
        _rs[name] = value;
    }
    return _rs;
}

/*删除url指定参数,返回url*/
// delParamsUrl('https://www.baidu.com?name=张三&age=24&sex=男', 'name')
// 返回结果-> "https://www.baidu.com?age=24&sex=男"
export function delParamsUrl(url, name){
    var baseUrl = url.split('?')[0] + '?';
    var query = url.split('?')[1];
    if (query.indexOf(name)>-1) {
        var obj = {}
        var arr = query.split("&");
        for (var i = 0; i < arr.length; i++) {
            arr[i] = arr[i].split("=");
            obj[arr[i][0]] = arr[i][1];
        };
        delete obj[name];
        var url = baseUrl + JSON.stringify(obj).replace(/[\"\{\}]/g,"").replace(/\:/g,"=").replace(/\,/g,"&");
        return url
    }else{
        return url;
    }
}

10.将两个数组合并成一个对象数组

let options = [];
let times = [30, 60, 120, 300, 420, 540, 720, 900, 1200];
let timesDesc = ["30分钟", "1小时", "2小时", "5小时", "7小时", "9小时", "12小时", "15小时", "20小时"];
将上面的2个数组 转化成下面的对象数组
/*
options=[
  {
    time: 30,
    timeDesc: "30分钟"
  },
  {
    time: 60,
    timeDesc: "1小时"
  },
  {
    time: 120,
    timeDesc: "2小时"
  },
]
*/

let size=times.length;
for(let i=0;i<size;i++){
  let a={};
  a.time=times[i];
  a.timeDesc=timesDesc[i];
  options.push(a);
}
console.log(options); // 得到转化结果

11.根据经纬度计算距离

/**
 * 计算经纬度
 * calcDistance(116.95400,39.95400,116.95300,39.95300)
 * 返回值为距离 单位千米(KM)
 */
export function calcDistance(lat1, lng1, lat2, lng2) {
  // console.log(lat1, lng1, lat2, lng2)
  var radLat1 = lat1 * Math.PI / 180.0;
  var radLat2 = lat2 * Math.PI / 180.0;
  var a = radLat1 - radLat2;
  var b = lng1 * Math.PI / 180.0 - lng2 * Math.PI / 180.0;
  var s = 2 * Math.asin(Math.sqrt(Math.pow(Math.sin(a / 2), 2) + Math.cos(radLat1) * Math.cos(radLat2) * Math.pow(Math.sin(
  b / 2), 2)));
  s = s * 6378.137;
  s = Math.round(s * 10000) / 10000;
  return s //  
}

12.将一个数组,拆分成几个子数组

/**
 * changeArrGroup([1,2,3,4,5,6,7,8,9],3)
 * 结果 -> [ [1,2,3], [4,5,6], [7,8,9] ]
 * 将一个数组,拆分成几个子数组
 */
export function changeArrGroup (arr, newArrLength) {
  let changeIndex = 0;
  let secondArr = [];
  while (changeIndex < arr.length) {
    secondArr.push(arr.slice(changeIndex, changeIndex+=newArrLength))
  }
  return secondArr;
}

13. localStorage 使用

/**
 * 存储localStorage
 */
export const setStore = (name, content) => {
    if (!name) return;
    if (typeof content !== 'string') {
        content = JSON.stringify(content);
    }
    window.localStorage.setItem(name, content);
}

/**
 * 获取localStorage
 */
export const getStore = name => {
    if (!name) return;
    return window.localStorage.getItem(name);
}

/**
 * 删除localStorage
 */
export const removeStore = name => {
    if (!name) return;
    window.localStorage.removeItem(name);
}

14 函数防抖/节流

/**
 * 函数防抖--不立即执行
 */
export const debounce = (fn, delay) => {
    // 记录上一次的延时器
    var timer = null;
    var delay = delay || 200;
    return function() {
        var args = arguments;
        var that = this;
        // 清除上一次延时器
        clearTimeout(timer)
        timer = setTimeout(function() {
            fn.apply(that, args)
        }, delay);
    }
}

/**
 * 函数防抖--立即执行
 */
export const debounce2 = (func,wait,immediate)=>{
    let timer;
    return function () {
        let context = this;
        let args = arguments;
        if (timer) clearTimeout(timer);
        if (immediate) {
            var callNow = !timer;
            timer = setTimeout(() => {
                timer = null;
            }, wait)
            if (callNow) func.apply(context, args)
        } else {
            timer = setTimeout(function(){
                func.apply(context, args)
            }, wait);
        }
    }
}


/**
 * 函数节流
 */
export const throttle = (fn, delay) => {
    var lastTime;
    var timer;
    var delay = delay || 200;
    return function() {
        var args = arguments;
        // 记录当前函数触发的时间
        var nowTime = Date.now();
        if (lastTime && nowTime - lastTime < delay) {
            clearTimeout(timer);
            timer = setTimeout(()=>{
                // 记录上一次函数触发的时间
                lastTime = nowTime;
                // 修正this指向问题
                fn.apply(this, args);
            }, delay);
        } else {
            lastTime = nowTime;
            fn.apply(this, args);
        }
    }
}

15. 其它操作

/*获取十六进制随机颜色*/
getRandomColor () {
    return '#' + (function(h) {
        return new Array(7 - h.length).join("0") + h;
    })((Math.random() * 0x1000000 << 0).toString(16));
}

/*图片加载*/
imgLoadAll(arr,callback){
    var arrImg = []; 
    for (var i = 0; i < arr.length; i++) {
        var img = new Image();
        img.src = arr[i];
        img.onload = function(){
            arrImg.push(this);
            if (arrImg.length == arr.length) {
                callback && callback();
            }
        }
    }
}

/*音频加载*/
loadAudio(src, callback) {
    var audio = new Audio(src);
    audio.onloadedmetadata = callback;
    audio.src = src;
}

/*DOM转字符串*/
domToStirng(htmlDOM){
    var div= document.createElement("div");
    div.appendChild(htmlDOM);
    return div.innerHTML
}

/*字符串转DOM*/
stringToDom(htmlString){
    var div= document.createElement("div");
    div.innerHTML=htmlString;
    return div.children[0];
}

/**
 * 光标所在位置插入字符,并设置光标位置
 * 
 * @param {dom} 输入框
 * @param {val} 插入的值
 * @param {posLen} 光标位置处在 插入的值的哪个位置
 */
setCursorPosition (dom,val,posLen) {
    var cursorPosition = 0;
    if(dom.selectionStart){
        cursorPosition = dom.selectionStart;
    }
    this.insertAtCursor(dom,val);
    dom.focus();
    console.log(posLen)
    dom.setSelectionRange(dom.value.length,cursorPosition + (posLen || val.length));
}

/*光标所在位置插入字符*/
insertAtCursor(dom, val) {
    if (document.selection){
        dom.focus();
        sel = document.selection.createRange();
        sel.text = val;
        sel.select();
    }else if (dom.selectionStart || dom.selectionStart == '0'){
        let startPos = dom.selectionStart;
        let endPos = dom.selectionEnd;
        let restoreTop = dom.scrollTop;
        dom.value = dom.value.substring(0, startPos) + val + dom.value.substring(endPos, dom.value.length);
        if (restoreTop > 0){
            dom.scrollTop = restoreTop;
        }
        dom.focus();
        dom.selectionStart = startPos + val.length;
        dom.selectionEnd = startPos + val.length;
    } else {
        dom.value += val;
        dom.focus();
    }
}

16. 千分位、现金数字转大写

/**
 * 千分位格式化
 * 1234567 -> 1,234,567
 * @param {String|Number} value
 */
export const thousands = (value, fractionDigits = 0) => {
  const regexp = /\d{1,3}(?=(\d{3})+(\.\d*)?$)/g
  return (Number(value).toFixed(fractionDigits) + '').replace(regexp, '$&,')
}

/**
 * 数字转为千分位字符
 * @param {Number} num
 * @param {Number} point 保留几位小数,默认2位
 */
function parseToThousandth(num, point = 2) {
  let [sInt, sFloat] = (Number.isInteger(num) ? `${num}` : num.toFixed(point)).split('.');
  sInt = sInt.replace(/\d(?=(\d{3})+$)/g, '$&,');
  return sFloat ? `${sInt}.${sFloat}` : `${sInt}`;
}

parseToThousandth(1234567); // '1,234,567'

/**
 * 现金数字转大写
 * 1234.567 -> 壹仟贰佰叁拾肆元伍角陆分柒厘
 * @param {String|Number} value
 */
export const upDigit = (value) => {
  const digit = ['零', '壹', '贰', '叁', '肆', '伍', '陆', '柒', '捌', '玖']
  const fraction = ['角', '分', '厘']
  const unit = [
    ['元', '万', '亿'],
    ['', '拾', '佰', '仟'],
  ]
  let s = ''
  let head = value < 0 ? '欠' : ''
  value = Math.abs(value)

  for (let i = 0; i < fraction.length; i++) {
    s += (digit[Math.floor(value * 10 * Math.pow(10, i)) % 10] + fraction[i]).replace(/零./, '')
  }

  s = s || '整'
  value = Math.floor(value)

  for (let i = 0; i < unit[0].length && value > 0; i++) {
    let p = ''
    for (let j = 0; j < unit[1].length && value > 0; j++) {
      p = digit[value % 10] + unit[1][j] + p
      value = Math.floor(value / 10)
    }
    s = p.replace(/(零.)*零$/, '').replace(/^$/, '零') + unit[0][i] + s
  }

  return (
    head +
    s
      .replace(/(零.)*零元/, '元')
      .replace(/(零.)+/g, '零')
      .replace(/^整$/, '零元整')
  )
}

17. 文件大小显示

/**
 * 文件大小显示转换
 * 12         -> 12.0 B
 * 98223445   -> 93.7 MB
 * 9822344566 -> 9.15 GB
 * @param {String|Number} bytes
 */
export const bytesToSize = (bytes) => {
  bytes = bytes.toString()
  if (bytes == 0) return '0 B'
  const k = 1024
  const i = Math.floor(Math.log(bytes) / Math.log(k))
  const sizes = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']
  return (bytes / Math.pow(k, i)).toPrecision(3) + ' ' + sizes[i]
}

18. 格式化手机号-手机号隐私保护

/**
 * 手机号隐私保护
 * 13866668888 -> 138****8888
 * @param {String|Number} value
 */
export const secretPhone = (value) => value.toString().replace(/(\d{3})(\d{4})(\d{4})/, '$1****$3')

/**
 * 格式化手机号
 * 13866668888 -> "138-6666-8888"
 * @param {*} value
 */
export const formatPhone = (value) => value.toString().replace(/(^\d{3}|\d{4}\B)/g, '$1-')

19. json数组对象排序(可以根据多个字段排序)

// 定义一个无序数组
const mockData = [
  { col_0: "粗抛槽", col_1: "初配", col_2: "时间", value: "9999", unit: "" },
  { col_0: "粗抛槽", col_1: "补液", col_2: "CDI", value: "1000", unit: "" },
  { col_0: "粗抛槽", col_1: "初配", col_2: "温度", value: "80", unit: "" },
  { col_0: "粗抛槽", col_1: "补液", col_2: "HDI", value: "9000", unit: "" },
  { col_0: "粗抛槽", col_1: "补液", col_2: "KOH", value: "800", unit: "" },
  { col_0: "粗抛槽", col_1: "初配", col_2: "KOH", value: "40000", unit: "" },
  { col_0: "预清洗槽", col_1: "初配", col_2: "温度", value: "70", unit: "" },
  { col_0: "制绒槽1", col_1: "初配", col_2: "温度", value: "82", unit: "" },
  { col_0: "制绒槽2", col_1: "初配", col_2: "温度", value: "82", unit: "" },
  { col_0: "制绒槽3", col_1: "初配", col_2: "温度", value: "82", unit: "" },
  { col_0: "慢提拉槽", col_1: "", col_2: "温度", value: "70", unit: "" },
  { col_0: "风干槽1", col_1: "", col_2: "温度", value: "90", unit: "" },
  { col_0: "风干槽2", col_1: "", col_2: "温度", value: "90", unit: "" },
  { col_0: "风干槽3", col_1: "", col_2: "温度", value: "90", unit: "" },
  { col_0: "风干槽4", col_1: "", col_2: "温度", value: "90", unit: "" },
  { col_0: "预清洗槽", col_1: "初配", col_2: "时间", value: "135", unit: "" },
  { col_0: "制绒槽1", col_1: "初配", col_2: "时间", value: "430", unit: "" },
  { col_0: "制绒槽2", col_1: "初配", col_2: "时间", value: "430", unit: "" },
  { col_0: "制绒槽3", col_1: "初配", col_2: "时间", value: "430", unit: "" },
  { col_0: "臭氧槽", col_1: "初配", col_2: "时间", value: "120", unit: "" },
  { col_0: "酸洗1槽", col_1: "初配", col_2: "时间", value: "", unit: "" },
  { col_0: "酸洗1槽", col_1: "初配", col_2: "时间", value: "", unit: "" },
  { col_0: "慢提拉槽", col_1: "", col_2: "时间", value: "10", unit: "" },
  { col_0: "风干槽1", col_1: "", col_2: "时间", value: "560", unit: "" },
  { col_0: "风干槽2", col_1: "", col_2: "时间", value: "560", unit: "" },
  { col_0: "风干槽3", col_1: "", col_2: "时间", value: "560", unit: "" },
  { col_0: "风干槽4", col_1: "", col_2: "时间", value: "560", unit: "" },
  { col_0: "预清洗槽", col_1: "补液", col_2: "CDI", value: "1000", unit: "" },
  { col_0: "预清洗槽", col_1: "补液", col_2: "H2O2", value: "500", unit: "" },
  { col_0: "预清洗槽", col_1: "补液", col_2: "HDI", value: "2000", unit: "" },
  { col_0: "预清洗槽", col_1: "补液", col_2: "KOH", value: "90", unit: "" },
  { col_0: "制绒槽1", col_1: "补液", col_2: "ADDI", value: "200", unit: "" },
  { col_0: "制绒槽1", col_1: "补液", col_2: "HDI", value: "10000", unit: "" }
];

// 方法一
/**
 * @param {Object} name 表示排序的第一个字段
 * @param {Object} minor 这个参数可选的,是一个函数,函数里面的参数是排序的第二个字段
*/
function compare(name, minor) {
  return function (o, p) {
    let a, b;
    if (o && p && typeof o === "object" && typeof p === "object") {
      a = o[name];
      b = p[name];
      if (a === b) {
        return typeof minor === "function" ? minor(o, p) : 0;
      }
      if (typeof a === typeof b) {
        return a < b ? -1 : 1;
      }
      return typeof a < typeof b ? -1 : 1;
    } else {
      throw "error";
    }
  };
}
// 使用方法
mockData.sort(compare('col_0', compare('col_1')));
mockData.sort(compare('col_0'));

// 方法二
/**根据数组对象中的某个属性值进行排序
 * 表示根据number属性降序排列;若第二个参数不传递,默认表示升序排序
 * @param attr 排序的属性 ['col_0','col_1'],根据一个字段或者多个字段排序
 * @param rev true表示升序排列,false降序排序
 * 
*/
function sortByArr(arr, rev) {
  if (rev == undefined) {
    rev = 1;
  } else {
    rev = rev ? 1 : -1;
  }
  return function (a, b) {
    for (let i = 0; i < arr.length; i++) {
      let attr = arr[i];
      if (a[attr] != b[attr]) {
        if (a[attr] > b[attr]) {
          return rev * 1;
        } else {
          return rev * -1;
        }
      }
    }
  };
}
// 使用方法 
mockData.sort(sortByArr(['col_0', 'col_1']), false)

20. json数组对象去重
https://segmentfault.com/a/1190000016418021?utm_source=tag-newest

这里去重包含2种,一种只是单纯去除重复的元素,去重重复的元素,并且对重复的元素求和累加

// 定义一个无序数组
const mockData = [
  { col_0: "粗抛槽", col_1: "初配", col_2: "时间", value: "9999", unit: "" },
  { col_0: "粗抛槽", col_1: "补液", col_2: "CDI", value: "1000", unit: "" },
  { col_0: "粗抛槽", col_1: "初配", col_2: "温度", value: "80", unit: "" },
  { col_0: "粗抛槽", col_1: "补液", col_2: "HDI", value: "9000", unit: "" },
  { col_0: "粗抛槽", col_1: "补液", col_2: "KOH", value: "800", unit: "" },
  { col_0: "粗抛槽", col_1: "初配", col_2: "KOH", value: "40000", unit: "" },
  { col_0: "预清洗槽", col_1: "初配", col_2: "温度", value: "70", unit: "" },
  { col_0: "制绒槽1", col_1: "初配", col_2: "温度", value: "82", unit: "" },
  { col_0: "制绒槽2", col_1: "初配", col_2: "温度", value: "82", unit: "" },
  { col_0: "制绒槽3", col_1: "初配", col_2: "温度", value: "82", unit: "" },
  { col_0: "慢提拉槽", col_1: "", col_2: "温度", value: "70", unit: "" },
  { col_0: "风干槽1", col_1: "", col_2: "温度", value: "90", unit: "" },
  { col_0: "风干槽2", col_1: "", col_2: "温度", value: "90", unit: "" },
  { col_0: "风干槽3", col_1: "", col_2: "温度", value: "90", unit: "" },
  { col_0: "风干槽4", col_1: "", col_2: "温度", value: "90", unit: "" },
  { col_0: "预清洗槽", col_1: "初配", col_2: "时间", value: "135", unit: "" },
  { col_0: "制绒槽1", col_1: "初配", col_2: "时间", value: "430", unit: "" },
  { col_0: "制绒槽2", col_1: "初配", col_2: "时间", value: "430", unit: "" },
  { col_0: "制绒槽3", col_1: "初配", col_2: "时间", value: "430", unit: "" },
  { col_0: "臭氧槽", col_1: "初配", col_2: "时间", value: "120", unit: "" },
  { col_0: "酸洗1槽", col_1: "初配", col_2: "时间", value: "", unit: "" },
  { col_0: "酸洗1槽", col_1: "初配", col_2: "时间", value: "", unit: "" },
  { col_0: "慢提拉槽", col_1: "", col_2: "时间", value: "10", unit: "" },
  { col_0: "风干槽1", col_1: "", col_2: "时间", value: "560", unit: "" },
  { col_0: "风干槽2", col_1: "", col_2: "时间", value: "560", unit: "" },
  { col_0: "风干槽3", col_1: "", col_2: "时间", value: "560", unit: "" },
  { col_0: "风干槽4", col_1: "", col_2: "时间", value: "560", unit: "" },
  { col_0: "预清洗槽", col_1: "补液", col_2: "CDI", value: "1000", unit: "" },
  { col_0: "预清洗槽", col_1: "补液", col_2: "H2O2", value: "500", unit: "" },
  { col_0: "预清洗槽", col_1: "补液", col_2: "HDI", value: "2000", unit: "" },
  { col_0: "预清洗槽", col_1: "补液", col_2: "KOH", value: "90", unit: "" },
  { col_0: "制绒槽1", col_1: "补液", col_2: "ADDI", value: "200", unit: "" },
  { col_0: "制绒槽1", col_1: "补液", col_2: "HDI", value: "10000", unit: "" }
];

第一种: 只是单纯去除重复的元素
/**
    * @param {Object} array 需要去除重复的数组对象
    * @param {Object} key 根据那个字段来去重
*/
function uniqueArray(array, key){
  let result = [array[0]];
  for(let i = 1; i < array.length; i++){
    let item = array[i];
    let repeat = false;
    for (let j = 0; j < result.length; j++) {
      if (item[key] === result[j][key]) {
        repeat = true;
        break;
      }
    }
    if (!repeat) {
      result.push(item);
    }
  }
  return result;
}
// 使用方法
console.log(uniqueArray(mockData, 'col_0'));

// 去重重复的元素,并且对重复的元素求和累加
/**
  * @param {Object} paylist 需要去除重复的数组对象
  * 对象中的 value字段 重复的会累加
  */
function UniquePay(paylist) {
  let payArr = [paylist[0]];
  for (let i = 1; i < paylist.length; i++) {
    let payItem = paylist[i];
    let repeat = false;
    for (let j = 0; j < payArr.length; j++) {
      if (payItem.col_0 === payArr[j].col_0) {
        payArr[j].value = parseFloat(payArr[j].value) + parseFloat(payItem.value);
        repeat = true;
        break;
      }
    }
    if (!repeat) {
      payArr.push(payItem);
    }
  }
  return payArr;
}
// 使用方法
console.log(UniquePay(mockData));

第三种 最简单去重 包含下面几种方法
const temp = {};  //用于判断某个字段重复
const result = []; // 去重最后的新数组
mockData.map(function (item, index) {
  if(!temp[item.col_0]){
    result.push(item);
    temp[item.col_0] = true;
  }
});

// 利用Map数据结构去重
function arrayNonRepeatfy(arr) {
  let map = new Map();
  let array = new Array();  // 数组用于返回结果
  for (let i = 0; i < arr.length; i++) {
    if(map.has(arr[i].col_0)) {  // 如果有该key值
      map.set(arr[i].col_0, true); 
    } else { 
      map.set(arr[i].col_0, false);   // 如果没有该key值
      array.push(arr[i]);
    }
  } 
  return array ;
}
arrayNonRepeatfy(mockData)

// 利用for嵌套for,然后splice去重(ES5中最常用)
function unique(arr){            
  for(var i=0; i<arr.length; i++){
    for(var j=i+1; j<arr.length; j++){
      if(arr[i].col_0===arr[j].col_0){         //第一个等同于第二个,splice方法删除第二个
        arr.splice(j,1);
        j--;
      }
    }
  }
    return arr;
}
unique(mockData)

// 利用includes
function unique(arr) {
    if (!Array.isArray(arr)) return
    var array =[];
    var array2 = []
    for(var i = 0; i < arr.length; i++) {
      if( !array.includes( arr[i].col_0) ) {//includes 检测数组是否有某个值
        array.push(arr[i].col_0);
        array2.push(arr[i])
      }
    }
    return array2
}

unique(mockData)

21. JS 数组对象根据某一相同key合并成新的数组

/********************需求是将具有相同school的对象合并为新的数组*******************/
let arr = [
  {
      name: '小明',
      age: 20,
      school: '清华'
  },
  {
     name: '小红',
     age: 21,
     school: '清华'
  },
  {
     name: '小白',
     age: 18,
     school: '北大'
  },
  {
     name: '小黄',
     age: 19,
     school: '北大'
  },
  {
     name: '小浪',
     age: 21,
     school: '哈佛'
  }
]
// 方法1
function handlerDatas(arr) {
  let obj = {};
  arr.forEach((item, index) => {
    let {
      school
    } = item;
    if (!obj[school]) {
      obj[school] = {
        school,
        children: []
      }
    }
    obj[school].children.push(item);
  });
  // 最终输出
  let data = Object.values(obj);
  return data
}

// 方法2
function handlerDatas(arr){
  // arr 传过来的原数组
  let tempArr = [];
  let endData = [];
  for (let i = 0; i < arr.length; i++) {
    if (tempArr.indexOf(arr[i].school) === -1) {
    // if (!tempArr.includes(arr[i].school)) {   // 这种判断也可以
      endData.push({
        school: arr[i].school,
        children: [arr[i]]
      });
      tempArr.push(arr[i].school);
    } else {
      for (let j = 0; j < endData.length; j++) {
        if (endData[j].school == arr[i].school) {
          endData[j].children.push(arr[i]);
          break;
        }
      }
    }
  }
  // console.log(endData); // 最终输出
  return endData
}

/****************************最终转化为下面这种********************************/
[
    {
        "school": "清华",
        "children": [
            {
                "name": "小明",
                "age": 20,
                "school": "清华"
            },
            {
                "name": "小红",
                "age": 21,
                "school": "清华"
            }
        ]
    },
    {
        "school": "北大",
        "children": [
            {
                "name": "小白",
                "age": 18,
                "school": "北大"
            },
            {
                "name": "小黄",
                "age": 19,
                "school": "北大"
            }
        ]
    },
    {
        "school": "哈佛",
        "children": [
            {
                "name": "小浪",
                "age": 21,
                "school": "哈佛"
            }
        ]
    }
]

/******************** 将数组对象改成对象数组***********************/
let arr = [
  { name: '小明',age: 20,school: 'qinghua',},
  { name: '小红',age: 21,school: 'qinghua',},
  { name: '小白',age: 18,school: 'beida',},
  { name: '小黄',age: 19,school: 'beida',},
  { name: '小浪',age: 21,school: 'hafo',},
]

function handlerDatas(arr){
  let obj = {};
  arr.forEach((item, index) => {
    let { school } = item;
    if (!obj[school]) {
      obj[school] = {
        school,
        children: []
      }
    }
    obj[school].children.push(item);
  });
  let data = Object.values(obj);
  let newData = {};

  data.forEach((item, i) => {
    let key = item.school;
    let value = item.children;
    newData[key] = value;
  });
  console.log(newData); // 最终输出
  return newData
}

22. json对象,转化为JSON数组

/**
{ suipian: 123, buliang: 456, chanliang: 789 }
         |
         V
         [
             {
                 "type": "suipian",
                 "value": 123
             },
             {
                 "type": "buliang",
                 "value": 456
             },
             {
                 "type": "chanliang",
                 "value": 789
             }
         ]
*/
function jsonToArray(obj){
  const arr = []
  for (let key in obj) {
    if(!obj.hasOwnProperty(key)){
      continue;
    }
    let o = {
      type: '',
      value: ''
    };
    o.type = key
    o.value = obj[key]
    arr.push(o)
  }
  return arr
}

23. json数组,转成json对象

/**
        const arr = [
            {
                "type": "suipian",
                "value": 123
            },
            {
                "type": "buliang",
                "value": 456
            },
            {
                "type": "chanliang",
                "value": 789
            }
        ]

        |
        V

        {
            suipian: 123, buliang: 456, chanliang: 789
        }
         */
        function arrayToJson (array) {
            const json = {}
            if(Array.isArray(array)) {
                for (let i=0; i<array.length;i++) {
                    if(array[i]){
                        json[array[i].type] = array[i].value
                    }
                }
            }
            return json    
        }

24. 排序混合的字母/数字数组

// 需求: 我有一个混合数组,我需要先按字母然后按数字排序
['A1', 'A10', 'A11', 'A12', 'A2', 'A3', 'A4', 'B10', 'B2', 'F1', 'F12', 'F3']
// 我如何将其排序为:['A1', 'A2', 'A3', 'A4', 'A10', 'A11', 'A12', 'B2', 'B10', 'F1', 'F3', 'F12']

let reA = /[^a-zA-Z]/g;
let reN = /[^0-9]/g;

function sortAlphaNum(a, b) {
  let aA = a.replace(reA,"");
  let bA = b.replace(reA,"");
  if (aA === bA) {
    let aN = parseInt(a.replace(reN,""), 10);
    let bN = parseInt(b.replace(reN,""), 10);
    return aN === bN ? 0 : aN > bN ? 1 : -1;
  } else {
    return aA > bA ? 1 : -1;
  }
}
// 使用方式
const arr = ['A1', 'A10', 'A11', 'A12', 'A2', 'A3', 'A4', 'B10', 'B2', 'F1', 'F12', 'F3']
const sortArr = arr.sort(sortAlphaNum)
console.log('排序后的数组:',sortArr)

CSS部分

1. rem适配封装

export function rem(doc, win) {
    let docEl = doc.documentElement;  //考虑以及兼容了 屏幕旋转的事件
    let resizeEvt = 'orientationchange' in window ? 'orientationchange' : 'resize'; let recalc = function () {
        var clientWidth = docEl.clientWidth; 
        if (!clientWidth) return; 
        if (clientWidth >= 750) {
            docEl.style.fontSize = '100px';
        } else {
            docEl.style.fontSize = 100 * (clientWidth / 750) + 'px';
        }
    }; 
    if (!doc.addEventListener) return;
    win.addEventListener(resizeEvt, recalc, false);                         // 屏幕大小以及旋转变化自适应
    doc.addEventListener('DOMContentLoaded', recalc, false);     // 页面初次打开自适应
    recalc();
};

(function (doc, win) {
    var docEl = doc.documentElement,
        resizeEvt = 'orientationchange' in window ? 'orientationchange' : 'resize',
        recalc = function () {
            var clientWidth = docEl.clientWidth;
            if (!clientWidth) return;
            docEl.style.fontSize = 15 * (clientWidth / 320) + 'px';
        };
    if (!doc.addEventListener) return;
    win.addEventListener(resizeEvt, recalc, false);
    doc.addEventListener('DOMContentLoaded', recalc, false);
})(document, window);

2. PC端重置样式初始化

/* normalize.css */
html {
  line-height: 1.15;
  /* 1 */
  -ms-text-size-adjust: 100%;
  /* 2 */
  -webkit-text-size-adjust: 100%;
  /* 2 */
}

body {
  margin: 0;
}

article,
aside,
footer,
header,
nav,
section {
  display: block;
}

h1 {
  font-size: 2em;
  margin: 0.67em 0;
}

figcaption,
figure,
main {
  /* 1 */
  display: block;
}

figure {
  margin: 1em 40px;
}

hr {
  box-sizing: content-box;
  /* 1 */
  height: 0;
  /* 1 */
  overflow: visible;
  /* 2 */
}

pre {
  font-family: monospace, monospace;
  /* 1 */
  font-size: 1em;
  /* 2 */
}

a {
  background-color: transparent;
  /* 1 */
  -webkit-text-decoration-skip: objects;
  /* 2 */
}

abbr[title] {
  border-bottom: none;
  /* 1 */
  text-decoration: underline;
  /* 2 */
  text-decoration: underline dotted;
  /* 2 */
}

b,
strong {
  font-weight: inherit;
}

b,
strong {
  font-weight: bolder;
}

code,
kbd,
samp {
  font-family: monospace, monospace;
  /* 1 */
  font-size: 1em;
  /* 2 */
}

dfn {
  font-style: italic;
}

mark {
  background-color: #ff0;
  color: #000;
}

small {
  font-size: 80%;
}

sub,
sup {
  font-size: 75%;
  line-height: 0;
  position: relative;
  vertical-align: baseline;
}

sub {
  bottom: -0.25em;
}

sup {
  top: -0.5em;
}

audio,
video {
  display: inline-block;
}

audio:not([controls]) {
  display: none;
  height: 0;
}

img {
  border-style: none;
}

svg:not(:root) {
  overflow: hidden;
}

button,
input,
optgroup,
select,
textarea {
  font-family: sans-serif;
  /* 1 */
  font-size: 100%;
  /* 1 */
  line-height: 1.15;
  /* 1 */
  margin: 0;
  /* 2 */
}

button,
input {
  /* 1 */
  overflow: visible;
}

button,
select {
  /* 1 */
  text-transform: none;
}

button,
html [type="button"],

/* 1 */

[type="reset"],
[type="submit"] {
  -webkit-appearance: button;
  /* 2 */
}

button::-moz-focus-inner,
[type="button"]::-moz-focus-inner,
[type="reset"]::-moz-focus-inner,
[type="submit"]::-moz-focus-inner {
  border-style: none;
  padding: 0;
}

button:-moz-focusring,
[type="button"]:-moz-focusring,
[type="reset"]:-moz-focusring,
[type="submit"]:-moz-focusring {
  outline: 1px dotted ButtonText;
}

fieldset {
  padding: 0.35em 0.75em 0.625em;
}

legend {
  box-sizing: border-box;
  /* 1 */
  color: inherit;
  /* 2 */
  display: table;
  /* 1 */
  max-width: 100%;
  /* 1 */
  padding: 0;
  /* 3 */
  white-space: normal;
  /* 1 */
}

progress {
  display: inline-block;
  /* 1 */
  vertical-align: baseline;
  /* 2 */
}

textarea {
  overflow: auto;
}

[type="checkbox"],
[type="radio"] {
  box-sizing: border-box;
  /* 1 */
  padding: 0;
  /* 2 */
}

[type="number"]::-webkit-inner-spin-button,
[type="number"]::-webkit-outer-spin-button {
  height: auto;
}

[type="search"] {
  -webkit-appearance: textfield;
  /* 1 */
  outline-offset: -2px;
  /* 2 */
}

[type="search"]::-webkit-search-cancel-button,
[type="search"]::-webkit-search-decoration {
  -webkit-appearance: none;
}

 ::-webkit-file-upload-button {
  -webkit-appearance: button;
  /* 1 */
  font: inherit;
  /* 2 */
}

details,

/* 1 */

menu {
  display: block;
}

summary {
  display: list-item;
}

canvas {
  display: inline-block;
}

template {
  display: none;
}

[hidden] {
  display: none;
}

/* reset */

html,
body,
h1,
h2,
h3,
h4,
h5,
h6,
div,
dl,
dt,
dd,
ul,
ol,
li,
p,
blockquote,
pre,
hr,
figure,
table,
caption,
th,
td,
form,
fieldset,
legend,
input,
button,
textarea,
menu {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

3. 移动端重置样式初始化

/* normalize.css */
html {
  line-height: 1.15;
  /* 1 */
  -ms-text-size-adjust: 100%;
  /* 2 */
  -webkit-text-size-adjust: 100%;
  /* 2 */
}

body {
  margin: 0;
}

article,
aside,
footer,
header,
nav,
section {
  display: block;
}

h1 {
  font-size: 2em;
  margin: 0.67em 0;
}

figcaption,
figure,
main {
  /* 1 */
  display: block;
}

figure {
  margin: 1em 40px;
}

hr {
  box-sizing: content-box;
  /* 1 */
  height: 0;
  /* 1 */
  overflow: visible;
  /* 2 */
}

pre {
  font-family: monospace, monospace;
  /* 1 */
  font-size: 1em;
  /* 2 */
}

a {
  background-color: transparent;
  /* 1 */
  -webkit-text-decoration-skip: objects;
  /* 2 */
}

abbr[title] {
  border-bottom: none;
  /* 1 */
  text-decoration: underline;
  /* 2 */
  text-decoration: underline dotted;
  /* 2 */
}

b,
strong {
  font-weight: inherit;
}

b,
strong {
  font-weight: bolder;
}

code,
kbd,
samp {
  font-family: monospace, monospace;
  /* 1 */
  font-size: 1em;
  /* 2 */
}

dfn {
  font-style: italic;
}

mark {
  background-color: #ff0;
  color: #000;
}

small {
  font-size: 80%;
}

sub,
sup {
  font-size: 75%;
  line-height: 0;
  position: relative;
  vertical-align: baseline;
}

sub {
  bottom: -0.25em;
}

sup {
  top: -0.5em;
}

audio,
video {
  display: inline-block;
}

audio:not([controls]) {
  display: none;
  height: 0;
}

img {
  border-style: none;
}

svg:not(:root) {
  overflow: hidden;
}

button,
input,
optgroup,
select,
textarea {
  font-family: sans-serif;
  /* 1 */
  font-size: 100%;
  /* 1 */
  line-height: 1.15;
  /* 1 */
  margin: 0;
  /* 2 */
}

button,
input {
  /* 1 */
  overflow: visible;
}

button,
select {
  /* 1 */
  text-transform: none;
}

button,
html [type="button"],

/* 1 */

[type="reset"],
[type="submit"] {
  -webkit-appearance: button;
  /* 2 */
}

button::-moz-focus-inner,
[type="button"]::-moz-focus-inner,
[type="reset"]::-moz-focus-inner,
[type="submit"]::-moz-focus-inner {
  border-style: none;
  padding: 0;
}

button:-moz-focusring,
[type="button"]:-moz-focusring,
[type="reset"]:-moz-focusring,
[type="submit"]:-moz-focusring {
  outline: 1px dotted ButtonText;
}

fieldset {
  padding: 0.35em 0.75em 0.625em;
}

legend {
  box-sizing: border-box;
  /* 1 */
  color: inherit;
  /* 2 */
  display: table;
  /* 1 */
  max-width: 100%;
  /* 1 */
  padding: 0;
  /* 3 */
  white-space: normal;
  /* 1 */
}

progress {
  display: inline-block;
  /* 1 */
  vertical-align: baseline;
  /* 2 */
}

textarea {
  overflow: auto;
}

[type="checkbox"],
[type="radio"] {
  box-sizing: border-box;
  /* 1 */
  padding: 0;
  /* 2 */
}

[type="number"]::-webkit-inner-spin-button,
[type="number"]::-webkit-outer-spin-button {
  height: auto;
}

[type="search"] {
  -webkit-appearance: textfield;
  /* 1 */
  outline-offset: -2px;
  /* 2 */
}

[type="search"]::-webkit-search-cancel-button,
[type="search"]::-webkit-search-decoration {
  -webkit-appearance: none;
}

 ::-webkit-file-upload-button {
  -webkit-appearance: button;
  /* 1 */
  font: inherit;
  /* 2 */
}

details,

/* 1 */

menu {
  display: block;
}

summary {
  display: list-item;
}

canvas {
  display: inline-block;
}

template {
  display: none;
}

[hidden] {
  display: none;
}

/* reset */

html,
body,
h1,
h2,
h3,
h4,
h5,
h6,
div,
dl,
dt,
dd,
ul,
ol,
li,
p,
blockquote,
pre,
hr,
figure,
table,
caption,
th,
td,
form,
fieldset,
legend,
input,
button,
textarea,
menu {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

html,
body {
  /* 禁止选中文本 */
  -webkit-user-select: none;
  user-select: none;
  font: Oswald, 'Open Sans', Helvetica, Arial, sans-serif
}

/* 禁止长按链接与图片弹出菜单 */

a,
img {
  -webkit-touch-callout: none;
}

/*ios android去除自带阴影的样式*/

a,
input {
  -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
}

input[type="text"] {
  -webkit-appearance: none;
}

4. 公共样式提取

/* 禁止选中文本 */
.usn{
    -webkit-user-select:none;
    -moz-user-select:none;
    -ms-user-select:none;
    -o-user-select:none;
    user-select:none;
}
/* 浮动 */
.fl { float: left; }
.fr { float: right; }
.cf { zoom: 1; }
.cf:after {
    content:".";
    display:block;
    clear:both;
    visibility:hidden;
    height:0;
    overflow:hidden;
}

/* 元素类型 */
.db { display: block; }
.dn { display: none; }
.di { display: inline }
.dib {display: inline-block;}
.transparent { opacity: 0 }

/*文字排版、颜色*/
.f12 { font-size:12px }
.f14 { font-size:14px }
.f16 { font-size:16px }
.f18 { font-size:18px }
.f20 { font-size:20px }
.fb { font-weight:bold }
.fn { font-weight:normal }
.t2 { text-indent:2em }
.red,a.red { color:#cc0031 }
.darkblue,a.darkblue { color:#039 }
.gray,a.gray { color:#878787 }
.lh150 { line-height:150% }
.lh180 { line-height:180% }
.lh200 { line-height:200% }
.unl { text-decoration:underline; }
.no_unl { text-decoration:none; }
.tl { text-align: left; }
.tc { text-align: center; }
.tr { text-align: right; }
.tj { text-align: justify; text-justify: inter-ideograph; }
.wn { /* 强制不换行 */
    word-wrap:normal;
    white-space:nowrap;
}
.wb { /* 强制换行 */
    white-space:normal;
    word-wrap:break-word;
    word-break:break-all;
}
.wp { /* 保持空白序列*/
    overflow:hidden;text-align:left;white-space:pre-wrap;word-wrap:break-word;word-break:break-all;
}
.wes { /* 多出部分用省略号表示 , 用于一行 */
    overflow:hidden;
    word-wrap:normal;
    white-space:nowrap;
    text-overflow:ellipsis;
}
.wes-2 { /* 适用于webkit内核和移动端 */
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 2;
    overflow: hidden;
} 
.wes-3 {
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 3;
    overflow: hidden;
}
.wes-4 {
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 4;
    overflow: hidden;
}

/* 溢出样式 */
.ofh { overflow: hidden; }
.ofs {overflow: scroll; }
.ofa {overflow: auto; }
.ofv {overflow: visible; }

/* 定位方式 */
.ps {position: static; }
.pr {position: relative;zoom:1; }
.pa {position: absolute; }
.pf {position: fixed; }

/* 垂直对齐方式 */
.vt {vertical-align: top; }
.vm {vertical-align: middle; }
.vb {vertical-align: bottom; }

/* 鼠标样式 */
.csd {cursor: default; }
.csp {cursor: pointer; }
.csh {cursor: help; }
.csm {cursor: move; }

/* flex布局 */
.df-sb {
    display:flex;
    align-items: center;
    justify-content: space-between;
}
.df-sa {
    display:flex;
    align-items: center;
    justify-content: space-around;
}

/* 垂直居中 */
.df-c {
    display: flex;
    align-items: center;
    justify-content: center;
}
.tb-c {
    text-align:center;
    display:table-cell;
    vertical-align:middle;
}
.ts-c {
    position: absolute;
    left: 50%; top: 50%;
    transform: translate(-50%, -50%);
}
.ts-mc {
    position: absolute;
    left: 0;right: 0;
    bottom: 0; top: 0;
    margin: auto;
}

/* 辅助 */
.mask-fixed-wrapper {
    width: 100%;
    height: 100%;
    position: fixed;
    left:0;top:0;
    background: rgba(0, 0, 0, 0.65);
    z-index: 999;
}
.bg-cover {
    background-size: cover;
    background-repeat: no-repeat;
    background-position: center center;
}
.bg-cover-all {
    background-size: 100% 100%;
    background-repeat: no-repeat;
    background-position: center center;
}