// ==UserScript==
// @name 工具函数tls
// @namespace http://tampermonkey.net/
// @version 0.1.7
// @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(['$0','temp1'])
windowProxy()
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
}
/** @描述 定义以对象形式 获取window属性值 */
function getLogObjectValue(arr,prefix = '',suffix = '_o',win2 = win) {
/** @描述 定义以对象形式 获取window属性值 */
arr.forEach((newKey) => {
Object.defineProperty(win2,`${prefix}${newKey}${suffix}`,{
get() {
return console.log('%O',win2[newKey])
}
})
})
}
/** @描述 代理window,读取属性时,即打印对象 */
function windowProxy(win2 = win) {
/** @描述 代理window,读取属性时,即打印对象 */
let result;
win2.wp_o = new Proxy(win2,{
get: function (obj,prop) {
result = obj[prop]
console.log(`🎏 ${prop}=%O`,result)
return result
}
});
}
if (win.enjoy_tl) {
console.error('win.enjoy_tl已经存在,请使用win.enjoy_tls')
if (!win.enjoy_tls) win.enjoy_tls = tools
return
}
win.enjoy_tl = tools
Object.defineProperty(tools,'fns',{
/** @描述 对象下的函数名列表 */
get() {
return Object.keys(tools)
}
})
})(window)