1. 程式人生 > 實用技巧 >一些常用的工具函式

一些常用的工具函式

1. 下載檔案到本地

 1 function downLoadFile(data,fileName){
 2     if (!data) {
 3         return
 4     }
 5     var blob = new Blob([data]); // <!document><head><meta charset="utf-8"></head><body><h1>測試</h1></body>
 6     if (window.navigator && window.navigator.msSaveOrOpenBlob) { //
for IE 7 window.navigator.msSaveOrOpenBlob(blob,fileName); 8 }else{ 9 let url = window.URL.createObjectURL(blob); 10 let link = document.createElement('a'); 11 link.style.display = 'none'; 12 link.href = url; 13 link.setAttribute('download', fileName);
14 15 document.body.appendChild(link); 16 link.click(); 17 } 18 }
View Code

2. 複製內容到剪貼簿:

// 複製內容到剪貼簿
function copyToClip(text, callback) {
    if(document.execCommand('Copy')){
        //建立input
        var inputZ = document.createElement('input');
        //新增Id,用於後續操作
        inputZ.setAttribute('id','inputCopy');
        
//獲取當前連結 inputZ.value = text; //建立的input新增到body document.body.appendChild(inputZ); //選中input中的值 document.getElementById('inputCopy').select(); //把值複製下來 document.execCommand('Copy') //刪除新增的input document.body.removeChild(inputZ); // 成功回撥1 typeof callback === 'function' && callback(1); }else{ // 失敗回撥2 typeof callback === 'function' && callback(2); } }
View Code

3. 全屏和退出全屏

// 全屏
function fullscreen(elem) {
    var docElm = elem || document.documentElement;
    if (docElm.requestFullscreen) {
        docElm.requestFullscreen();
    } else if (docElm.mozRequestFullScreen) {
        docElm.mozRequestFullScreen();
    } else if (docElm.webkitRequestFullScreen) {
        docElm.webkitRequestFullScreen();
    } else if (docElm.msRequestFullscreen) {
        docElm.msRequestFullscreen();  
    }
}
  
// 退出全屏
function exitFullscreen() {
    if (document.exitFullscreen) {  
        document.exitFullscreen();
    } else if (document.mozCancelFullScreen) {
        document.mozCancelFullScreen();
    } else if (document.webkitCancelFullScreen) {
        document.webkitCancelFullScreen();
    } else if (document.msExitFullscreen) {
        document.msExitFullscreen();
    }
}
View Code

4. 獲取裝置資訊

// from: vue.js
function getPlatForm () {
    var inBrowser = typeof window !== 'undefined';
    var inWeex = typeof WXEnvironment !== 'undefined' && !!WXEnvironment.platform;
    var weexPlatform = inWeex && WXEnvironment.platform.toLowerCase();
    var UA = inBrowser && window.navigator.userAgent.toLowerCase();
    var isIE = UA && /msie|trident/.test(UA);
    var isIE9 = UA && UA.indexOf('msie 9.0') > 0;
    var isEdge = UA && UA.indexOf('edge/') > 0;
    var isAndroid = (UA && UA.indexOf('android') > 0) || (weexPlatform === 'android');
    var isIOS = (UA && /iphone|ipad|ipod|ios/.test(UA)) || (weexPlatform === 'ios');
    var isChrome = UA && /chrome\/\d+/.test(UA) && !isEdge;
    var isPhantomJS = UA && /phantomjs/.test(UA);
    var isFF = UA && UA.match(/firefox\/(\d+)/);
    return {
        inBrowser, inWeex, weexPlatform, UA, isIE, isIE9, isEdge, isAndroid, isIOS, isChrome, isPhantomJS, isFF
    }
}
View Code

  

5. 日期格式化

function dateFormat(data, fmt) {
    !fmt && (fmt = 'yyyy/MM/dd hh:mm:ss')
    if (typeof data === 'number') {
      data = data.toString().substr(0, 13)
    }
    if (typeof data === 'string') {
      data = new Date(parseInt(data))
    }
    let o = {
      'M+': data.getMonth() + 1, // 月份
      'd+': data.getDate(), //
      'h+': data.getHours(), // 小時
      'm+': data.getMinutes(), //
      's+': data.getSeconds(), //
      'q+': Math.floor((data.getMonth() + 3) / 3), // 季度
      S: data.getMilliseconds() // 毫秒
    }
    if (/(y+)/.test(fmt)) {
      fmt = fmt.replace(RegExp.$1, (data.getFullYear() + '').substr(4 - RegExp.$1.length))
    }
    for (let k in o) {
      if (new RegExp('(' + k + ')').test(fmt)) {
        fmt = fmt.replace(
          RegExp.$1,
          RegExp.$1.length === 1 ? o[k] : ('00' + o[k]).substr(('' + o[k]).length)
        )
      }
    }
    return fmt
  }
View Code

  

6. 字串格式化(模板)

function compile(template){
  var evalExpr = /<%=(.+?)%>/g;
  var expr = /<%([\s\S]+?)%>/g;

  template = template
    .replace(evalExpr, '`); \n echo( $1 );\n echo(`')
    .replace(expr, '`);\n $1 \n echo(`');

  template = 'echo(`' + template + '`);';

  var script = '\n' +
    'var output = "";\n' + 
    'function echo(html){ \n' +
      'output += html; \n' +
    '};\n' + 
    template + '\n' +
    'return output; \n';

  return new Function('data', script);
}
View Code

  

7. 獲取周/根據周獲取日期範圍

// 獲取周: 一個月最多可以跨 6周, 31天, 首尾恰好位於起始時間
// from: https://stackoverflow.com/questions/9045868/javascript-date-getweek
function getWeek(timeStr) {
    var _this = new Date(timeStr);
    // We have to compare against the first monday of the year not the 01/01
    // 60*60*24*1000 = 86400000
    // 'onejan_next_monday_time' reffers to the miliseconds of the next monday after 01/01
  
    var day_miliseconds = 86400000,
        onejan = new Date(_this.getFullYear(), 0, 1, 0, 0, 0),
        onejan_day = (onejan.getDay() == 0) ? 7 : onejan.getDay(),
        days_for_next_monday = (8 - onejan_day),
        onejan_next_monday_time = onejan.getTime() + (days_for_next_monday * day_miliseconds),
        // If one jan is not a monday, get the first monday of the year
        first_monday_year_time = (onejan_day > 1) ? onejan_next_monday_time : onejan.getTime(),
        this_date = new Date(_this.getFullYear(), _this.getMonth(), _this.getDate(), 0, 0, 0), // This at 00:00:00
        this_time = this_date.getTime(),
        days_from_first_monday = Math.round(((this_time - first_monday_year_time) / day_miliseconds));
  
    var first_monday_year = new Date(first_monday_year_time);
  
    // We add 1 to "days_from_first_monday" because if "days_from_first_monday" is *7,
    // then 7/7 = 1, and as we are 7 days from first monday,
    // we should be in week number 2 instead of week number 1 (7/7=1)
    // We consider week number as 52 when "days_from_first_monday" is lower than 0,
    // that means the actual week started before the first monday so that means we are on the firsts
    // days of the year (ex: we are on Friday 01/01, then "days_from_first_monday"=-3,
    // so friday 01/01 is part of week number 52 from past year)
    // "days_from_first_monday<=364" because (364+1)/7 == 52, if we are on day 365, then (365+1)/7 >= 52 (Math.ceil(366/7)=53) and thats wrong
  
    return (days_from_first_monday >= 0 && days_from_first_monday < 364) ? Math.ceil((days_from_first_monday + 1) / 7) : 52;
}

// 對 week 的一步反運算, 計算情況: 2019,3: 2019年第3周, 對應是哪天到哪天;
function getWeekRange(year, week, tpl) {
    var day_miliseconds = 86400000,
        onejan = new Date(year, 0, 1, 0, 0, 0),
        onejan_day = (onejan.getDay() == 0) ? 7 : onejan.getDay(),
        days_for_next_monday = (8 - onejan_day),
        onejan_next_monday_time = onejan.getTime() + (days_for_next_monday * day_miliseconds),
        first_monday_year_time = (onejan_day > 1) ? onejan_next_monday_time : onejan.getTime(),
        target_week_monday_time = first_monday_year_time + day_miliseconds * 7 * (week - 1),
        target_week_sunday_time = target_week_monday_time + day_miliseconds * 6 - 1000;
  
    return [formatDate(target_week_monday_time, tpl || 'yyyy-MM-dd'), formatDate(target_week_sunday_time, tpl || 'yyyy-MM-dd')]
}
View Code

8. 深拷貝

// 深拷貝
function deepCopy(obj) {
    var copy;
 
    // Handle the 3 simple types, and null or undefined
    if (null == obj || "object" != typeof obj) return obj;
 
    // Handle Date
    if (obj instanceof Date) {
        copy = new Date();
        copy.setTime(obj.getTime());
        return copy;
    }
 
    // Handle Array
    if (obj instanceof Array) {
        copy = [];
        for (var i = 0, len = obj.length; i < len; i++) {
            copy[i] = deepCopy(obj[i]);
        }
        return copy;
    }
 
    // Handle Object
    if (obj instanceof Object) {
        copy = {};
        for (var attr in obj) {
            if (obj.hasOwnProperty(attr)) copy[attr] = deepCopy(obj[attr]);
        }
        return copy;
    }
 
    if (isPrimitiveValue(obj)) {
        copy = obj;
        return copy;
    }
    throw new Error("Unable to copy obj! Its type isn't supported.");
}
View Code

9. 是否相同物件

function deepEqual(x, y) {
  var core_toString = Object.prototype.toString
  var ta = core_toString.call(x)
  var tb = core_toString.call(y)

  if (x === y) {
    return true
  }
  if (ta !== tb) {
    return false
  }
  if (!(typeof x == 'object' && x != null) || !(typeof y == 'object' && y != null)) {
    return false
  }

  if (Object.keys(x).length != Object.keys(y).length) {
    return false
  }
  for (var prop in x) {
    if (y.hasOwnProperty(prop)) {
      if (!deepEqual(x[prop], y[prop])) {
        return false
      }
    } else {
      return false
    }
  }

  return ta === '[object Date]' ? x.valueOf() == y.valueOf() : true
}
View Code

10. 找出兩個物件的差異欄位

function diff(lobj, robj, change, path, key) {
  var ltype = type(lobj),
      rtype = type(robj);
  
  var ldefined = ltype !== 'undefined'
  var rdefined = rtype !== 'undefined'

  path = path || []
  var currentPath = path.slice(0)
  if (typeof key !== 'undefined' && key !== null) {
    currentPath.push(key)
  }
  
  if (!ldefined && rdefined) {
    change.push({
      type: 'add',
      path: currentPath,
      rhs: robj
    })
  } else if (ldefined && !rdefined) {
    change.push({
      type: 'delete',
      path: currentPath,
      lhs: lobj
    })
  } else if (ltype !== rtype) {
    change.push({
      type: 'edit',
      path: currentPath,
      lhs: lobj,
      rhs:robj
    })
  } else {
    if (isPrimaty(lobj)) {
      if (lobj !== robj) {
        change.push({
          type: 'edit',
          path: currentPath,
          lhs: lobj,
          rhs: robj
        })
      }
    } else if (ltype === 'object') {
      var aKeys = Object.keys(lobj)
      var pKeys = Object.keys(robj)
      var ckeys = unique(aKeys.concat(pKeys))
      var p;

      for (var i=0; i<ckeys.length; i++) {
          diff(lobj[ckeys[i]], robj[ckeys[i]], change, currentPath, ckeys[i])
      }
    } else if (ltype === 'array') {
      var maxLen = Math.max.apply(null, [lobj.length, robj.length]);
      for(var i=0; i<maxLen; i++) {
        diff(lobj[i], robj[i], change, currentPath, i)
      }
    // Date, ExpExc 等
    } else if (ltype === 'date'){
      if (lobj.valueOf() !== robj.valueOf()) {
        change.push({
          type: 'edit',
          path: currentPath,
          lhs: lobj,
          rhs: robj
        })
      }
    }
  }
}
 

輔助方法:

// 簡單實現
function unique (arr) {
    var res = [];
    for(var i = 0; i < arr.length; i++) {
    if (res.indexOf(arr[i]) === -1) {
        res.push(arr[i])
    }
    }
    return res
}

function isPrimaty (value) {
  return (
    typeof value === 'number' ||
    typeof value === 'string' ||
    typeof value === 'boolean' ||
    typeof value === 'undefined' ||
    typeof value === 'symbol' ||
    typeof value === 'bigint' ||
    (typeof value === 'object' && value === null)
  )
}

function type(input) {
    return ({}).toString.call(input).slice(8, -1).toLowerCase();
}
 

示例:

var obj1 = {
  a: 123,
  b: { b1: 12, b2: 22, b3: '123' },
  c: [1, 4],
  d: { c1: 4 },
  e: null,
  f: new Date()
}

var obj2 = {
  a: 123,
  b: { b1: 12, b2: 33 },
  c: [4, 1],
  d: { c1: 4 },
  f: new Date('2020-12-30')
}

var res = []
diff(obj1, obj2, res);

res => 
[
    {
        "type":"edit",
        "path":["b","b2"],
        "lhs":22,
        "rhs":33
    },{
        "type":"delete",
        "path":["b","b3"],
        "lhs":"123"
    },{
        "type":"delete",
        "path":["e"],
        "lhs":null
    },{
        "type":"edit",
        "path":["f"],
        "lhs":"2020-07-02T08:28:00.640Z",
        "rhs":"2020-12-30T00:00:00.000Z"
    }
]    
View Code