工具函数tls

挂载到window下一级属性集合-常用工具函数

目前为 2023-06-28 提交的版本。查看 最新版本

// ==UserScript==
// @name         工具函数tls
// @namespace    http://tampermonkey.net/
// @version      0.1.5
// @description  挂载到window下一级属性集合-常用工具函数
// @author       Enjoy_li
// @match        *://*/*
// @homepage      https://greasyfork.org/zh-CN/scripts/468302-%E5%B7%A5%E5%85%B7%E5%87%BD%E6%95%B0tls
// @license MIT
// @icon         https://foruda.gitee.com/avatar/1671100286067517749/4867929_enjoy_li_1671100285.png!avatar60
// @grant        none
// ==/UserScript==

; (function (win) {

  getLogObjectValue(['v$0','vtemp1'])

  const tools = {
    backPrototype,
    createPlainFile,
    getRegMobile,
    phoneFormat,
    getRegName,
    getRegEmail,
    getRegIDCard,
    getQuery,
    toSearch,
    transformThousandth,
    deleteProperty,
    asyncRequire,
    transformData,
    previewFile,
    dateUtil,
    toWithOpener,
    downloadFile,
    base64ToBlob,
    base64ImgtoFile,
    isHasBtnPower,
    getBrowerEnv,
    formatReportDataToStr,
    copyStrToClipboard,
    getPropertiesOfObj,
    lgd,
    lgd0,
    lgdt1,
    getPrototypeChainOfObject,
    getLogObjectValue
  }

  function getPrototypeChainOfObject(Obj) {
    /** @描述 对象原型链 */

    let idx = 0
    let str = `${Obj.name || '参数'}的原型链是: `

    next(Obj)

    return str

    /** @描述 递归 */
    function next(obj) {
      let ObjType = Object.toLocaleString.call(obj)
      let ObjFlag = ObjType.match(/^\[object ([a-zA-Z]+)\]/)?.[1] || typeof ObjType
      str += `第 ${idx} 级【${ObjFlag}】.__proto__ ▶️ `
      idx++
      if (obj.__proto__) {
        next(obj.__proto__)
      } else {
        str += `第 ${idx} 级【null】`
      }
    }
  }

  function lgdt1(...rest) {
    /** @描述 以对象形式打印 $0 */
    console.log(`temp1 ==%O`,temp1,...rest)
  }

  function lgd(...args) {
    /** @描述 以对象形式打印 temp1 */

    let [desc,...rest] = args
    if (rest.length && typeof desc === 'string') {
      return console.log(`${desc} %O`,...rest)
    }
    console.log(`%O`,...args)
  }

  function lgd0(...rest) {
    /** @描述 以对象形式打印 $0 */
    console.log(`$0 ==%O`,$0,...rest)
  }

  function backPrototype(resourceObj) {
    /**
   * @description 对象原型链:继承谁的属性和方法
   * @param {*} resourceObj
   * @returns {*} string
   */

    let str = ''

    next(resourceObj)

    str = str + 'null'

    console.log(`%c 该对象原型链是:`,'color:red',str)
    return str

    function next(obj) {
      let ObjType = Object.toLocaleString.call(obj)
      let ObjFlag = ObjType.match(/^\[object ([a-zA-Z]+)\]/)?.[1] || '无'
      str = str + ObjFlag + ' + .__proto__ >> '
      if (obj.__proto__) {
        next(obj.__proto__)
      }
    }
  }


  function createPlainFile(content = { a: 'a' },name = 'name') {
    /**
   * @description 创建文本文件
   * @param {string} [content={ a: 'a' }]
   * @param {string} [name='name']
   */

    // 下载保存json文件
    var eleLink = document.createElement("a");
    eleLink.download = name + '.json';
    // 字符内容转变成blob地址
    var data = JSON.stringify(content,undefined,4);
    var blob = new Blob([data],{ type: "text/json" });
    eleLink.href = URL.createObjectURL(blob);
    // 触发点击
    eleLink.click();
    // 然后移除
  }

  function getRegMobile() {
    /** @描述 正则 - 手机号 */
    return /^1[2|3|4|5|6|7|8|9][\d]{9}$/
  }

  function phoneFormat(phone = '') {
    /** @描述 格式化 - 手机号 */
    if (!phone || !/^(?:(?:\+|00)86)?1[3-9]\d{9}$/.test(phone)) return;
    phone = phone.replace(/\D/g,'').slice(0,11);
    phone = phone
      .replace(/^(\d{3})/,'$1  ')
      .replace(/(\d{4})/,'$1  ')
      .replace(/[\s]+$/,'')
    return phone;
  }

  function getRegName() {
    /** @描述 正则 - 姓名 */

    return /^[0-9|A-Za-z|\u4e00-\u9fa5|\s]+$/
  }


  function getRegEmail() {
    /** @描述 正则 - 邮箱 */

    return /^[_a-z0-9-]+(\.[_a-z0-9-]+)*@[a-z0-9-]+(\.[a-z0-9-]+)*(\.[a-z]{2,4})$/i
  }

  function getRegIDCard() {
    /** @描述 正则 - 大陆身份证号码 */
    return /^[1-9]\d{7}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}$|^[1-9]\d{5}[1-9]\d{3}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}([0-9]|X)$/
  }

  function getQuery(search = window.location.search) {
    /** @描述 获取 url 参数 */

    const query = {}
    search
      .substr(1)
      .split('&')
      .forEach((str) => {
        const strArr = str.split('=')
        const key = strArr[0]

        if (!key) return

        let val = decodeURIComponent(strArr[1])
        try {
          val = JSON.parse(val)
        } catch (err) { }
        query[key] = val
      })
    return query
  }

  function toSearch(obj = {}) {
    /** @描述 转换成 url search */
    const arr = Object.keys(obj).map((key) => {
      let val = obj[key]

      if (typeof val !== 'string') {
        try {
          val = JSON.stringify(val)
        } catch (err) {
          console.error(err)
        }
      }

      return `${key}=${encodeURIComponent(val)}`
    })
    return '?' + arr.join('&')
  }


  function transformThousandth(value,fixed) {
    /**
 * 格式化金额 千分符
 * @param value
 * @param fixed
 */

    const needFixed = fixed != null
    const num = Number(value)
    if (isNaN(num)) {
      return needFixed ? (0).toFixed(fixed) : '0'
    }
    // return (needFixed ? num.toFixed(fixed) : num.toString()).replace(/(\d{1,3})(?=(\d{3})+(?:$|\.))/g, '$1,')
    const str = needFixed ? num.toFixed(fixed) : num.toString()
    const arr = str.split('.')

    let result = arr[0] ? arr[0].replace(/(?=(?!\b)(\d{3})+$)/g,',') : '0'
    if (arr[1] != null) {
      result += `.${arr[1]}`
    }

    return result
  }


  function deleteProperty(obj = {},v = [undefined,null,'']) {
    /**
 * 删除指定值的属性
 * @param obj
 */

    const res = {}
    const isArray = Array.isArray(v)
    for (const key in obj) {
      if (isArray) {
        if (!v.includes(obj[key])) res[key] = obj[key]
      } else {
        if (obj[key] !== v) res[key] = obj[key]
      }
    }
    return res
  }


  function asyncRequire(url,name,type) {
    /**
 * 通过插入标签以加载 js/css 文件
 * @param {String} url 需要载入的 js/css url
 * @param {String} name 文件载入后挂载到 window 下的变量名
 * @param {String} type 文件类型 默认取后缀名
 */

    return new Promise((resolve,reject) => {
      const head =
        document.head || document.getElementsByTagName('head')[0] || document.body
      const filePath = url.split('?')[0]
      const ext = filePath.substring(filePath.lastIndexOf('.') + 1)

      if (document.getElementById(`async-require-${name || 'unknown'}`)) {
        return resolve(name ? window[name] : 'loaded')
      }

      let element
      if (ext == 'js' || type == 'js') {
        element = document.createElement('script')
        element.src = url
        element.onload = (e) => resolve(name ? window[name] : e)
      } else if (ext == 'css' || type == 'css') {
        element = document.createElement('link')
        element.rel = 'stylesheet'
        element.type = 'text/css'
        element.href = url
        element.onload = resolve
      } else {
        return console.warn('好像有点不对劲...请指定文件类型: js | css')
      }

      element.id = `async-require-${name}`
      element.onerror = reject
      head.appendChild(element)
    })
  }


  function transformData(sourceData,relation) {
    /**
 * 返回数据
 * @param {Array} sourceData 原数组
 * @param {Array} 映射字段
 */

    return sourceData.map((item) => {
      const [key,name] = relation
      return {
        label: item[name],
        value: item[key],
      }
    })
  }

  function previewFile(fileUrl) {
    /**
 * 在线预览文件
 * @param  {String}  fileUrl  静态资源地址
 */

    let link = document.createElement('a')
    link.href = fileUrl
    let ext = (link.pathname.split('.')[1] || '').toLowerCase()

    const allowedExt = {
      bmp: 1,
      gif: 1,
      jpg: 1,
      jpeg: 1,
      png: 1,
      apng: 1,
      webp: 1,
      htm: 1,
      html: 1,
      pdf: 1,
    }

    if (ext && allowedExt[ext]) {
      const url = `https://static.hrwork.com/tools/pdfviewer/index.html?file=${encodeURIComponent(
        fileUrl
      )}`
      if (window?.__ZPA_CRX) {
        return void dispatchEvent(new CustomEvent('$create_tab',{ detail: url }))
      }
      window.open(url)
    } else {
      alert(`不支持在线预览此类型(${ext ?? ''})文件`)
    }
  }


  function dateUtil(time = new Date()) {
    /**
 * 获取特定格式日期
 * date: 可以为日期字符串、日期对象,不传参数默认当前系统时间
 * format: 输出日期时间格式, 不传参数默认 YYYY-MM-DD HH:mm:ss 格式
 * 例:
 * dateUtil().format()
 * // 2022-06-16 11:56:02
 *
 * // 不传入日期,默认以当前日期,格式化为特定格式日期
 * dateUtil().format('YYYY年MM月DD日 (周W) HH时mm分ss秒')
 * // 2022年06月16日 (周四) 12时01分51秒
 *
 * // 传入指定日期(string | date),格式化为指定格式日期(string)
 * dateUtil('2015.7.12').format('YYYY年MM月DD日 HH时mm秒ss分 星期W')
 * // 2015年07月12日 00时00分00秒 星期三
 */

    time = typeof time === 'string' ? time.replace(/-/g,'/') : time
    const date = isNaN(new Date(time)) ? time : new Date(time);
    return { date,format };
    function format(rule = 'YYYY-MM-DD HH:mm:ss') {
      const weeks = ['日','一','二','三','四','五','六']
      const padStart = (d) => (d + '').padStart(2,'0')
      const M = date.getMonth() + 1 + ''
      const D = date.getDate() + ''
      const H = date.getHours() + ''
      const m = date.getMinutes() + ''
      const s = date.getSeconds() + ''
      return rule
        .replace('YYYY',date.getFullYear())
        .replace('MM',padStart(M))
        .replace('M',M)
        .replace('DD',padStart(D))
        .replace('D',D)
        .replace('HH',padStart(H))
        .replace('H',H)
        .replace('mm',padStart(m))
        .replace('m',m)
        .replace('ss',padStart(s))
        .replace('s',s)
        .replace(/W/,weeks[date.getDay()])
        .replace(/w/,date.getDay())
    }
  }


  function toWithOpener(href,options = {}) {
    /**
 * 共享opener跳转
 * @param { Object } router  如:
 * @param { Object } options  如:
 */

    const { target = '_blank',routes } = options
    const win = window.open(href,target)
    // 设置新打开页面的面包屑
    if (routes && Array.isArray(routes)) {
      const cloneRoutes = [...routes]
      cloneRoutes.shift()
      cloneRoutes[cloneRoutes.length - 1] = {
        ...cloneRoutes[cloneRoutes.length - 1],
        a: true,
        path: '/zhaopintong/' + location.hash,
      }
      win.sessionStorage.parent_routes = JSON.stringify(cloneRoutes)
    }
    return win
  }


  function downloadFile(href,fileName = '') {
    /**
 * 通过url一键下载图片
 * @param { String } href  如:
 * @param { String } fileName  如:
 */

    if (!href) {
      return
    }
    let aLink = document.createElement('a')
    aLink.download = fileName + Date.now()
    aLink.href = href
    aLink.click()
  }

  function base64ToBlob(base64Code) {
    /**
     * base64转Blob对象
     * @param { String } code  如:
     */

    const parts = base64Code.split(';base64,')
    const contentType = parts[0].split(':')[1]
    const raw = window.atob(parts[1])
    const rawLength = raw.length
    const uint8Array = new Uint8Array(rawLength)
    for (var i = 0; i < rawLength; i++) {
      uint8Array[i] = raw.charCodeAt(i)
    }
    return new Blob([uint8Array],{ type: contentType })
  }


  function base64ImgtoFile(base64Code,filename = 'file') {
    /**
 * base64转文件对象
 * @param { String } base64Code  如:
 * @param { String } filename  如:
 */

    let arr = base64Code.split(',')
    let mime = arr[0].match(/:(.*?);/)[1]
    let suffix = mime.split('/')[1]
    let bstr = atob(arr[1])
    let n = bstr.length
    let u8arr = new Uint8Array(n)
    while (n--) {
      u8arr[n] = bstr.charCodeAt(n)
    }
    return new File([u8arr],`${filename}.${suffix}`,{
      type: mime,
    })
  }


  function isHasBtnPower(powerList = [],code = '') {
    /**
 * @description 判断角色是否有页面级按钮的权限
 * @param {*} [powerList=[]]
 * @param {string} [code='']
 * @returns {*}  {boolean}
 */

    if (!code) return false

    if (typeof code === 'string') code = [code]

    for (const value of code) {
      if (powerList?.includes?.(value)) return true
    }
    return false
  }



  function getBrowerEnv() {
    /** @描述 判断当前浏览器运行环境 */

    const userAgent = window.navigator.userAgent.toLowerCase()
    const agents = ["Android","iPhone","SymbianOS","Windows Phone","iPad","iPod"]
    // 是否为支付宝环境
    const isAliPay = /alipayclient/.test(userAgent)
    // 是否为淘宝环境
    const isTaoBao = /windvane/.test(userAgent)
    // 是否为企业微信环境
    const isWxWork = /wxwork/.test(userAgent)
    // 是否为微信环境
    const isWeChat = /micromessenger/.test(userAgent) && !isWxWork
    // 是否为移动端
    const isPhone = agents.some(x => new RegExp(x.toLocaleLowerCase()).test(userAgent))
    return { isAliPay,isTaoBao,isWxWork,isWeChat,isPhone }
  }


  //
  function formatReportDataToStr(arr = [],headerLabel = []) {
    /** @描述 格式化报表数据拼接成字符串,以便复制到剪贴板 */

    return arr.reduce(
      (pre,cur) => {
        return (
          pre +
          headerLabel.reduceRight((pre2,cur2) => {
            return `${cur[cur2.key]}\t${pre2}`
          },'\n')
        )
      },
      headerLabel.reduceRight((pre,cur) => {
        return `${cur.title}\t${pre}`
      },'\n')
    )
  }


  function copyStrToClipboard(value) {
    /** @描述 把字符串复制到剪贴板 */

    const textarea = document.createElement('textarea')
    textarea.value = value
    document.body.appendChild(textarea)
    textarea.select()
    document.execCommand('Copy')
    document.body.removeChild(textarea)
  }

  async function copyStrToClipboardOfNavigator(value) {
    /** @描述 把字符串复制到剪贴板 */

    return await navigator.clipboard.writeText(value)
  }


  function getPropertiesOfObj({ obj = {},keys = [] }) {
  /**
 * @描述 获取对象的指定属性集合
 * @param {*} { obj = {}, keys = [] }
 * @returns {*}
 */

    let newObj = {}
    keys.forEach((key) => {
      newObj[key] = obj[key]
    })
    return newObj
  }


  function getLogObjectValue(arr,win = window) {
    /** @描述 定义以对象形式 获取window属性值 */
    arr.forEach((newKey) => {
      Object.defineProperty(win,newKey,{
        get() {
          return console.log('%O',win[newKey.slice(1)])
        }
      })
    })
  }




  if (win.tl) {
    console.error('win.tl已经存在,请使用win.tls')
    if (!win.tls) win.tls = tools
    return
  }
  win.tl = tools

  Object.defineProperty(tools,'fns',{
    /** @描述 对象下的函数名列表 */
    get() {
      return Object.keys(tools)
    }
  })
})(window)