我的工具
Ten skrypt nie powinien być instalowany bezpośrednio. Jest to biblioteka dla innych skyptów do włączenia dyrektywą meta // @require https://update.greasyfork.org/scripts/435697/1742073/mylib.js
//==UserScript==
// @name mylib260125
// @match *://*/*
// @description 需要兼容油猴环境和非油猴环境(如博客园)
// @grant GM_setValue
// @grant GM_getValue
// @grant GM_deleteValue
// @grant GM_listValues
// @grant GM.xmlHttpRequest
//==/UserScript==
;(function(){
"use strict";
const win = unsafeWindow ?? window,myxhr = GM.xmlHttpRequest ?? null,
info = win.info = GM_info ?? (GM?.info ?? {script:{name:'Userscript',namespace:'Nonamespace'}});
win.my=new My(win);//初始化
function My(win){//构造函数,需配合实例方法,与this,prototype有关
win.al=win.alert;
win.cl=win.console.log;
win.cc=win.console.clear;
win.ce=win.console.error;
win.dq=selector=>document.qs(selector);
win.dqa=selector=>document.qsa(selector);
win.si=win.setInterval;
win.st=win.setTimeout;
win.mysv=function(name, value) {//增/改
typeof GM_setValue==='function'?GM_setValue(name, value):localStorage.setItem(`${getScriptIdentifier()}_${name}`, value);
}
win.mygv=function(name, defvalue) { //查
if(typeof GM_getValue==='function')return GM_getValue(name, defvalue)
else{
if ((`${getScriptIdentifier()}_${name}`) in localStorage) return localStorage.getItem(`${getScriptIdentifier()}_${name}`);
else return defvalue;
}
}
win.myas=css=>win.myz.myappend('style',css);//function和lambda this指向不同,后者没有prototype、arguments,后者不能new/作为构造函数;
win.myaddbtns=(...args)=>{//myaddbtns(()=>{},e=>{confirm(e.target.id)},function outerHTML(e){prompt(e.target.outerHTML)},function test(e){return 1},function event(ev){cl(ev)})
args.forEach(arg=>{//{func:async function f(ev){...},title:'...'}
if(arg instanceof Function) win.mybtns.myappend('button',arg.name,`className`,'my-btn').ael('mouseup',arg);
else{//如非function,均为json
const btn=win.mybtns.myappend('input','','value',arg.func.name,'type','button',`className`,'my-btn','title',arg.title).ael('mouseup',arg.func);
if(arg.img) btn.style.backgroundImage=`url(${arg.img})`
}
})
return win.mybtns;
}
//My.静态方法 My.prototype实例方法(如本案例中my.prototype.constructor.toString())
// My.prototype.test1=function(){};My.test2=function(){}
EventTarget.prototype.mybefore=function(tagName,innerHTML,...attributes){//myz.mybefore('test','content','key','value').ael('click',()=>{al(1)})
const el=document.createElement(tagName);
el.innerHTML=innerHTML;
for(let i=0;i<attributes.length;i+=2) el[attributes[i]]=attributes[i+1];
this.before(el);
return el;
}
EventTarget.prototype.qs=Document.prototype.qs=function(selector){return this.querySelector(selector)||null}
EventTarget.prototype.qsa=Document.prototype.qsa=function(selector){return this.querySelectorAll(selector)||null}
EventTarget.prototype.myappend=function(tagName,innerHTML,...attributes){//myz.myappend('test','content','key','value').ael("click",()=>{al(1)}).myappend('y','test','idk','true','data-s')
const el=document.createElement(tagName);
el.innerHTML=innerHTML;
for(let i=0;i<attributes.length;i+=2) el[attributes[i]]=attributes[i+1];
this.appendChild(el);
return el;
}
EventTarget.prototype.myinsert=function(tagName, innerHTML,...attributes) {//myz.myinsert('test','content','key','value').ael('',()=>{al(1)})
const el=document.createElement(tagName);
el.innerHTML=innerHTML;
for (let i=0; i < attributes.length; i += 2) el[attributes[i]]=attributes[i + 1];
const firstChild=this.firstChild;
this.insertBefore(el,firstChild);
return el;
}
EventTarget.prototype.myafter=function(tagName,innerHTML,...attributes){//myz.myafter('test','content','key','value').ael("click",()=>{al(1)})
const el=document.createElement(tagName);
el.innerHTML=innerHTML;
for(let i=0;i<attributes.length;i+=2) el[attributes[i]]=attributes[i+1];
this.after(el);
return el;
}
EventTarget.prototype.ael=function(event,callback){//Element 和 Document 都实现了 EventTarget 接口,为更通用改Element为EventTarget
this.addEventListener(event,callback);
return this;
}
EventTarget.prototype.rel=function(event,handler){
this.removeEventListener(event,handler);
return this;
}
NodeList.prototype.removeEach=function(){//.forEach(e=>e.remove())
this.forEach(e=>e.remove());
};
NodeList.prototype.clickEach=function(){
this.forEach(e=>e.click());
};
win.myms2date=timestamp=>{//myms2date(Date.now())
const d=new Date(typeof timestamp==="number"?timestamp:Date.now()),f=n=>String(n).padStart(2,'0');
return`${d.getFullYear()}${f(d.getMonth()+1)}${f(d.getDate())}${f(d.getHours())}${f(d.getMinutes())}`;//${f(d.getSeconds())}${String(d.getMilliseconds()).padStart(3,'0')}
}
win.myBindDrag=el=>{//鼠标拖动
el.ael('mousedown',ev=>{
ev.stopPropagation()//ev.preventDefault();
const rect=el.getBoundingClientRect(); // 获取元素实际位置
let startX=ev.clientX-rect.left; // 使用视口绝对坐标
let startY=ev.clientY-rect.top;
const move=e=>{
const dx=e.clientX-startX,dy=e.clientY-startY; // 保持相对位移计算
el.style.transform=`translate(${dx}px,${dy}px)`;
},up=()=>{
document.rel('mousemove',move);
document.rel('mouseup',up);
};
document.ael('mousemove',move);
document.ael('mouseup',up);
});
}
win.mylockprop=function(obj,prop,value){//lock property;mylockprop(document,"title")
Object.defineProperty(obj,prop,{
set:v=>value,get:()=>value
});
}
win.myaddas=(...urls)=>urls.forEach(async(url,index)=>{//必须配合@connect
await myxhr({url:url}).then(resp=>resp.responseText).then(html=>{//myaddas("https://www.bilibili.com/","https://www.example.com/")
const doc=new DOMParser().parseFromString(html,'text/html'),title=doc.title;
win.mybtns.myappend('a',index+title,'href',url,`className`,'my-a my-btn');
}).catch(err=>{//跨域了
win.cl('跨域了'+err)
win.mybtns.myappend('a',`框${index}`,'href',url,`className`,'my-a my-btn');
});
});
win.mywait=time=>new Promise(resolve=> setTimeout(resolve,time));
win.mywaitele=(selector,timeout=3e4)=>{//查找ele,超时30000
return new Promise((resolve,reject)=>{
const 间隔=500,startTime=Date.now(),i=setInterval(()=>{
const el=win.dq(selector);
if (el){
clearInterval(i);
resolve(el);//找到
} else if (Date.now() - startTime > timeout){
clearInterval(i);
reject(`Timeout waiting ${selector}.`);//超时
}//继续找
},间隔);
});
}
win.mywaiteles=(selector,timeout=3e4)=>new Promise((resolve,reject)=>{//查找eles
const intervalTime=500,startTime=Date.now(),i=win.si(()=>{
const els=win.dqa(selector);
if (els.length>0){
clearInterval(i);
resolve(els);
} else if(Date.now() - startTime > timeout){
clearInterval(i);
reject(`Timeout waiting ${selector}.`);
}
},intervalTime);
});
win.myshowlv=()=>{//当前页面第几层
let level=0,currentWindow=win;
do{level++;
// al(level+currentWindow.location.href);
if(currentWindow === currentWindow.top) break;
currentWindow=currentWindow.parent;
}while(currentWindow.parent);
win.mybtns.myappend('a',`第${level}层`,'href',win.location.href,'className','my-a');
}
win.mydv=function(name) {//删
typeof GM_deleteValue==='function'?GM_deleteValue(name):localStorage.removeItem(`${getScriptIdentifier()}_${name}`);
}
win.mylv=function() {//查2
if(typeof GM_listValues==='function')return GM_listValues();
else{
let values =[],prefix =getScriptIdentifier(),prelen =getScriptIdentifier().length;
for (let i =0; i < localStorage.length; i++) if (localStorage.key(i).substr(0, prelen)===prefix) values.push(localStorage.key(i).substr(prelen+1));
return values;
}
}
My.divideStr=(str,char)=>Array.from(str).join(char);//以特定字符分隔字符串
My.reverseStr=str=>str.split('').reverse().join('');//反转str
function getScriptIdentifier(){
const scriptNamespace=typeof info.script.namespace==='string'?info.script.namespace.trim():'Nonamespace',scriptName=(typeof info.script.name==='string'&&info.script.name.trim().length > 0)?info.script.name.trim():'Userscript';
return `${scriptNamespace}-${scriptName}`;
}
return My;
}
})()