草庐IT

前端常用函数封装

吴知木 2023-03-28 原文

常用函数封装

获取某日期若干个工作日后的日期

* 参数: 
*   time: [String] 给定日期 yyyy-MM-dd
*   itervalByDay: [Number] 相隔工作日
*   separator: [String] 年月日分隔符
* 返回:
*   rq:[String] 匹配的日期yyyy-MM-dd
var getworkday = function(time, itervalByDay, separator = '-'){
  var str = time.split("-");
  
  var date = getDate();
  date.setUTCFullYear(str[0], str[1] - 1, str[2]);
  date.setUTCHours(0, 0, 0, 0);
  
  var millisceonds =date.getTime();
  for(var i = 1; i <= itervalByDay; i++){
    millisceonds += 24 * 60 * 60 * 1000;
    date.setTime(millisceonds);
    // 如果是周末,计数i回退1,既跳过
    if(date.getDay() == 0 || date.getDay() == 6) i--;
  }
  
  var year = date.getFullYear();
  var month = (date.getMonth() + 1);
  var day = date.getDate();
  var rq = year + separator + month + separator + day;
  
  return rq;
}

解析URL参数

* 参数: 
*   url: [String] 解析的URL,可选,不传该值默认本地href
* 返回:
*   obj:[Object] 参数集合对象
function getQueryParam(url) {
    const href = url || window.location.href;
    let args = href.split('?');
    
    // 没有参数直接返回{}
    if (args[0] === href) {
        return {};
    }
    
    var hrefarr = args[1].split('#')[0].split('&');
    var obj = {};
    for (var i = 0; i < hrefarr.length; i++) {
        hrefarr[i] = hrefarr[i].split('=');
        obj[hrefarr[i][0]] = hrefarr[i][1];
    }
    return obj;
}

格式化日期

* 参数: 
*   date: 时间戳 [Date]
*   isTime: 是否返回具体时间 [Boolean]
*   separator: 年月日分隔符 [String]
* 返回:
*   isTime: false => yyyy-MM-dd [String]
*   isTime: true => yyyy-MM-dd HH:mm:ss [String]
const formatDate = (date, isTime = false, separator = '-') => {
  const year = date.getFullYear()
  const month = date.getMonth() + 1
  const day = date.getDate()
  let d = [year, month, day].map(_formatNumber).join(separator)
  if (isTime) {
    const hour = date.getHours()
    const minute = date.getMinutes()
    const second = date.getSeconds()
    const time = [hour, minute, second].map(_formatNumber).join(':')

    d = `${d} ${time}`
  }
  return d
}
const _formatNumber = n => {
  n = n.toString()
  return n[1] ? n : '0' + n
}

// padStart()补齐日期位数
formatDate() {
  const date = new Date()
  const year = date.getFullYear().toString().padStart(4, '0')
  const month = (date.getMonth() + 1).toString().padStart(2, '0')
  const day = date.getDate().toString().padStart(2, '0')
  const result = `${year}-${month}-${day}`
  return result
}

解析身份证号码信息

* 参数: 
*   IdCard: [String] 身份证号码
*   type: [Number] 1/2/3 
* 返回:
*   type:1 => birthday [String] 出生日期
*   type:2 => sex [Number] 性别
*   type:3 => age [Number] 年龄
formatIdCard (IdCard, type) {
  if (type === 1) {
    // 获取出生日期
    var birthday = IdCard.substring(6, 10) + '-' + IdCard.substring(10, 12) '-' + IdCard.substring(12, 14)
    return birthday
  }
  if (type === 2) {
    // 获取性别
    if (parseInt(IdCard.substr(16, 1)) % 2 === 1) {
      return '1' // 男
    } else {
      return '2' // 女
    }
  }
  if (type === 3) {
    // 获取年龄
    var ageDate = new Date()
    var month = ageDate.getMonth() + 1
    var day = ageDate.getDate()
    var age = ageDate.getFullYear() - IdCard.substring(6, 10) - 1
    if (IdCard.substring(10, 12) < month || IdCard.substring(10, 12) === mont&& IdCard.substring(12, 14) <= day) {
      age++
    }
    if (age <= 0) {
      age = 1
    }
    return age
  }
}

微信小程序wx.request封装

* 1.输出完整接口日志
* 2.统一配置请求头、响应参数
* 3.统一管理请求响应操作(成功、失败)
request ({
  url,
  header,
  data = {},
  code = 'errCode', // 接口返回的业务标识
  method = 'POST',
  dataType = 'json',
  timeout = 10000,
  success = () => {},
  fail = () => {},
  complete = () => {}
}) {
  wx.showLoading({ title: '正在加载中', mask: true })
  return wx.request({
    url,
    data,
    method,
    header: {
      'content-type': 'application/json',
      token: this.globalData.token,
      ...header,
    },
    timeout,
    complete: res => {
      wx.hideLoading()
      // 打印信息
      console.log('');
      console.group(`---- ${url} ----`)
      console.log('Params', data)
      console.log('Header', {
        'content-type': 'application/json',
        token: this.globalData.token,
        ...header,
      })
      console.log('Response', res)
      console.info(`#### ${url} ####`)
      console.groupEnd()
      complete(res)
      // 返回成功
      if (res.data && +res.data[code] === 1) {
        return success(res.data)
      }
      // 返回错误
      fail(res.data)
    }
  })
}

获取图片base64

* 参数:
*   file {file object} 文件对象
* 返回:
*   {Promise}
async function imgToBase64 (file) {
  return new Promise((resolve,reject) => {
    const reader = new FileReader()
    reader.readAsDataURL(file)
    reader.onload = e => {
      resolve(e.target.result)
    }
    reader.onerror = err => {
        reject(err)
    }
  })
}

图片压缩

* 原理: 把图片宽度、高度调小
* @param file {file object | file base64}
* @param {width, height}:压缩图片宽高
* @returns {Promise}
* 
* Tip: 与imgToBase64()配合使用效果更佳
async function imgToCompressed (file, {
  width,
  height
}) {
  if (typeof file === 'object') {
    file = await imgToBase64(file)
  }

  return new Promise(resolve => {
    var image = new Image()
    image.src = file

    image.onload = () => {
      const _width = image.width
      const _height = image.height
      const canvas = document.createElement('canvas')
      const context = canvas.getContext('2d')
      let data = ''
      if (width && width > _width) {
        width = _width
        height = _height
      } else {
        // 等比例缩放
        width = width || Math.floor(_width * height / _height)
        height = height || Math.floor(width * _height / _width)
      }

      canvas.width = width
      canvas.height = height

      context.drawImage(image, 0, 0, width, height)
      data = canvas.toDataURL('image/jpeg').replace('data:image/jpeg;base64,', '')

      resolve(data)
    }
  })
}

前端搜索+分页

// 模糊搜索
function searchList() {
  const search = this.search
  const pageIndex = this.pageIndex
  const pageSize = this.pageSize
  
  if (search) {
    // filter() 方法创建一个新的数组,新数组中的元素是通过检查指定数组中符合条件的所有元素。
    // 注意: filter() 不会对空数组进行检测。
    // 注意: filter() 不会改变原始数组。
    return this.list.filter(data => {
      // some() 方法用于检测数组中的元素是否满足指定条件;
      // some() 方法会依次执行数组的每个元素:
      // 如果有一个元素满足条件,则表达式返回true , 剩余的元素不会再执行检测;
      // 如果没有满足条件的元素,则返回false。
      // 注意: some() 不会对空数组进行检测。
      // 注意: some() 不会改变原始数组。
      return Object.keys(data).some(key => {
        // indexOf() 返回某个指定的字符在某个字符串中首次出现的位置,如果没有找到就返回-1;
        // 该方法对大小写敏感!所以之前需要toLowerCase()方法将所有查询到内容变为小写。
        return (String(data[key]).toLowerCase().indexOf(search) > -1).slice((pageIndex - 1) * pageSize, pageIndex * pageSize)
      })
    })
  }
  return this.list
}

判断数据类型方法

* 判断数据类型方法
* @param {any} data 待判断类型的数据
* @returns {string}
const _typeof = function (data) {
    const value = /\[object (\w+)\]/.exec(
        Object.prototype.toString.call(data)
    );
    return value ? value[1].toLowerCase() : '';
}

// 简化版-判断效果一致
const _typeof = function (data) {
    return Object.prototype.toString.call(data).slice(8, -1)
}

// Test
_typeof('123')      //"string"
_typeof(123)        //"number"
_typeof(123n)       //"bigint"
_typeof(null)       //"null"
_typeof(undefined)  //"undefined"
_typeof({})         //"object"
_typeof([])         //"array"
_typeof(/123/)      //"regexp"

base64解码

* base64解码
* 优化中文乱码问题
* @param {String} b64Str 待解码的base64数据
* @returns {string}
function b64ToUtf8(b64Str) {
  return decodeURIComponent(window.atob(b64Str).split('').map(c => '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2)).join(''))
}

// atob()解码不支持中文
// base64编码前先对中文URL转码
window.btoa(encodeURIComponent(str))

冒泡排序

* 冒泡排序
* 比较相邻的元素。如果第一个比第二个大,就交换他们两个,对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。在这一点,最后的元素应该会是最大的数。
* @param {Array} arr 待排序的数组
* @returns {Array}
function bubbleSort(arr) {
  const len = arr.length
  for (var i = 0; i < n; i++) {
    // 每次冒泡完毕,右侧新固定一个较大值
    for (var j = 1; j < n - i; j++) {
      // 比较,交换大的于右侧
      if (arr[j - 1] > arr[j]) {
        [arr[j - 1], arr[j]] = [arr[j], arr[j - 1]]
      }
    }
  }
  return arr
}

bubbleSort([5, 2, 4, 6, 1, 3]) // 输出[1, 2, 3, 4, 5, 6]


// 常见优化方法
// 1.添加交换记录标志
// 用于标志某一趟排序过程中是否有数据交换,如果进行某一趟排序时并没有进行数据交换,则说明数据已经按要求排列好,可立即结束排序,避免不必要的比较过程。

插入排序

* 插入排序
* 插入排序的工作方式像许多人排序一手扑克牌,拿一张牌依次对比手上的牌组然后插入到牌组合适位置,重复直至最后一张。
* @param {Array} arr 待排序的数组
* @returns {Array}
function insertionSort(arr) {
  // 手上牌组
  let newArr = [arr[0]]
  let len = arr.length

  // 从左边开始,每次拿一个与已排列好的数组进行比较
  for (let i = 1; i < len; i++) {
    for (let j = 0; j < i; j++) {
      // 若拿的牌小于手上某张牌,则插入该牌前方
      if (arr[i] <= newArr[j]) {
        newArr.splice(j, 0, arr[i])
        break
      } 
      // 若拿的牌比最后一张都还大,则排在最后(注意:i = newArr.length)
      if (j === i - 1) {
        newArr.push(arr[i])
      }
    }
  }
  return newArr
}

insertionSort([5, 2, 4, 6, 1, 3]) // 输出[1, 2, 3, 4, 5, 6]

顺序/逆序 排序

* 顺序/逆序 排序
* @param {Array} arr 待排序的数组
* @returns {Array}
function _sort(arr) {
    return arr.sort((a,b) => {
        return a - b
        // return b - a 逆序
    })
}

_sort([1, 4, 2]) // 输出[1, 2, 4]

选择排序

* 选择排序
* 首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置。再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。
* @param {Array} arr 待排序的数组
* @returns {Array}
function selectionSort(arr) {
    var len = arr.length;
    var minIndex, temp;
    for (var i = 0; i < len - 1; i++) {
        minIndex = i;
        for (var j = i + 1; j < len; j++) {
            if (arr[j] < arr[minIndex]) {  // 寻找最小的数
                minIndex = j; // 将最小数的索引保存
            }
        }
        // 索引没改变则表明当前项位置正确,无需变换位置
        if(minIndex === i) continue
        [arr[i], arr[minIndex]] = [arr[minIndex], arr[i]]
    }
    return arr
}

selectionSort([5, 2, 4, 6, 1, 3]) // 输出[1, 2, 3, 4, 5, 6]

有关前端常用函数封装的更多相关文章

  1. ruby-on-rails - Rails 常用字符串(用于通知和错误信息等) - 2

    大约一年前,我决定确保每个包含非唯一文本的Flash通知都将从模块中的方法中获取文本。我这样做的最初原因是为了避免一遍又一遍地输入相同的字符串。如果我想更改措辞,我可以在一个地方轻松完成,而且一遍又一遍地重复同一件事而出现拼写错误的可能性也会降低。我最终得到的是这样的:moduleMessagesdefformat_error_messages(errors)errors.map{|attribute,message|"Error:#{attribute.to_s.titleize}#{message}."}enddeferror_message_could_not_find(obje

  2. ruby - 在没有 sass 引擎的情况下使用 sass 颜色函数 - 2

    我想在一个没有Sass引擎的类中使用Sass颜色函数。我已经在项目中使用了sassgem,所以我认为搭载会像以下一样简单:classRectangleincludeSass::Script::FunctionsdefcolorSass::Script::Color.new([0x82,0x39,0x06])enddefrender#hamlengineexecutedwithcontextofself#sothatwithintemlateicouldcall#%stop{offset:'0%',stop:{color:lighten(color)}}endend更新:参见上面的#re

  3. ruby-on-rails - 在 ruby​​ 中使用 gsub 函数替换单词 - 2

    我正在尝试用ruby​​中的gsub函数替换字符串中的某些单词,但有时效果很好,在某些情况下会出现此错误?这种格式有什么问题吗NoMethodError(undefinedmethod`gsub!'fornil:NilClass):模型.rbclassTest"replacethisID1",WAY=>"replacethisID2andID3",DELTA=>"replacethisID4"}end另一个模型.rbclassCheck 最佳答案 啊,我找到了!gsub!是一个非常奇怪的方法。首先,它替换了字符串,所以它实际上修改了

  4. ruby - 在 Ruby 中有条件地定义函数 - 2

    我有一些代码在几个不同的位置之一运行:作为具有调试输出的命令行工具,作为不接受任何输出的更大程序的一部分,以及在Rails环境中。有时我需要根据代码的位置对代码进行细微的更改,我意识到以下样式似乎可行:print"Testingnestedfunctionsdefined\n"CLI=trueifCLIdeftest_printprint"CommandLineVersion\n"endelsedeftest_printprint"ReleaseVersion\n"endendtest_print()这导致:TestingnestedfunctionsdefinedCommandLin

  5. ruby - 在 Ruby 中按名称传递函数 - 2

    如何在Ruby中按名称传递函数?(我使用Ruby才几个小时,所以我还在想办法。)nums=[1,2,3,4]#Thisworks,butismoreverbosethanI'dlikenums.eachdo|i|putsiend#InJS,Icouldjustdosomethinglike:#nums.forEach(console.log)#InF#,itwouldbesomethinglike:#List.iternums(printf"%A")#InRuby,IwishIcoulddosomethinglike:nums.eachputs在Ruby中能不能做到类似的简洁?我可以只

  6. C51单片机——实现用独立按键控制LED亮灭(调用函数篇) - 2

    说在前面这部分我本来是合为一篇来写的,因为目的是一样的,都是通过独立按键来控制LED闪灭本质上是起到开关的作用,即调用函数和中断函数。但是写一篇太累了,我还是决定分为两篇写,这篇是调用函数篇。在本篇中你主要看到这些东西!!!1.调用函数的方法(主要讲语法和格式)2.独立按键如何控制LED亮灭3.程序中的一些细节(软件消抖等)1.调用函数的方法思路还是比较清晰地,就是通过按下按键来控制LED闪灭,即每按下一次,LED取反一次。重要的是,把按键与LED联系在一起。我打算用K1来作为开关,看了一下开发板原理图,K1连接的是单片机的P31口,当按下K1时,P31是与GND相连的,也就是说,当我按下去时

  7. ruby-on-rails - 将字符串转换为 ruby​​-on-rails 中的函数 - 2

    我需要一个通过输入字符串进行计算的方法,像这样function="(a/b)*100"a=25b=50function.something>>50有什么方法吗? 最佳答案 您可以使用instance_eval:function="(a/b)*100"a=25.0b=50instance_evalfunction#=>50.0请注意,使用eval本质上是不安全的,尤其是当您使用外部输入时,因为它可能包含注入(inject)的恶意代码。另请注意,a设置为25.0而不是25,因为如果它是整数a/b将导致0(整数)。

  8. ruby - 在 ruby​​ 中使用 .try 函数和 .map 函数 - 2

    我需要从json记录中获取一些值并像下面这样提取curr_json_doc['title']['genre'].map{|s|s['name']}.join(',')但对于某些记录,curr_json_doc['title']['genre']可以为空。所以我想对map和join()使用try函数。我试过如下curr_json_doc['title']['genre'].try(:map,{|s|s['name']}).try(:join,(','))但是没用。 最佳答案 你没有正确传递block。block被传递给参数括号外的方法

  9. ruby - 是否可以从也在该模块中的类内部调用模块函数 - 2

    在这段Ruby代码中:ModuleMClassC当我尝试运行时出现“'M:Module'的未定义方法'helper'”错误c=M::C.new("world")c.work但直接从另一个类调用M::helper("world")工作正常。类不能调用在定义它们的同一模块中定义的模块函数吗?除了将类移出模块外,还有其他解决方法吗? 最佳答案 为了调用M::helper,你需要将它定义为defself.helper;结束为了进行比较,请查看以下修改后的代码段中的helper和helper2moduleMclassC

  10. ruby - 将运算符传递给函数? - 2

    也许这听起来很荒谬,但我想知道这对Ruby是否可行?基本上我有一个功能...defadda,bc=a+breturncend我希望能够将“+”或其他运算符(例如“-”)传递给函数,这样它就类似于...defsuma,b,operatorc=aoperatorbreturncend这可能吗? 最佳答案 两种可能性:以方法/算子名作为符号:defsuma,b,operatora.send(operator,b)endsum42,23,:+或者更通用的解决方案:采取一个block:defsuma,byielda,bendsum42,23,

随机推荐