s94-web
Version:
常用的web工具方法封装---牧人与鱼
676 lines (665 loc) • 28.7 kB
JavaScript
import s94 from '../../s94-js/s94.mjs.js'
var s94_web = (function (global) {
let document = global?.document;
if (!document) return console.error('缺少 document 对象!');
/**执行回调函数或者返回dom对象
* @param {Function|String} data 如果传入 Function ,等效于s94方法,如果传入字符,会返回s94_web.dom对象
* @param {Number} os s94方法的os参数
* @returns {s94_web.dom|Promise<*>|void}
*/
var s94_web = function(data, os) {
if(typeof data === "function") {
return s94(data, os);
}else {
return new s94_web.dom(data || []);
}
}
for (var k in s94) {s94_web[k] = s94[k];}
s94_web.cache.default_engine = global.sessionStorage;
s94_web.jsonp = s94.unifyRequest({
send(setup){
setup.jsonpCallback = setup.jsonpCallback || 'jsonp_'+(new Date().getTime());
setup.jsonp = setup.jsonp || 'callback';
let _this = this;
global[setup.jsonpCallback] = function(res){
setup.response.data = res;
setup.response.body = setup.jsonpCallback+'('+JSON.stringify(res)+')';
_this.callback(setup, 'success');
};
let script = setup.script = document.createElement("script");
script.onload = function(e) {
setup.response.code = 200;
setup.response.headers['content-type'] = 'application/javascript';
_this.callback(setup, 'complete');
document.documentElement.removeChild(script);
}
script.onerror = function(e){
setup.response.data = setup.response.body = (e.message || 'js加载失败:'+script.src);
_this.callback(setup, 'error');
_this.callback(setup, 'complete');
document.documentElement.removeChild(script);
}
script.src = setup.url + (setup.url.indexOf('?') == -1?'?':'&') + setup.jsonp + '=' + setup.jsonpCallback;
document.documentElement.appendChild(script);
return setup;
}
})
function get_os(){
if (typeof global.navigator !== 'object') return;
let res = 0;
if (/MicroMessenger/i.test(global.navigator.userAgent)) res |= s94.OS_H5_WECHAT;
if (/Android/i.test(global.navigator.userAgent)) {
res |= s94.OS_H5_ANDROID;
}else if (/iPhone|iPad/i.test(global.navigator.userAgent)){
res |= s94.OS_H5_IOS
}else{
res |= s94.OS_H5_PC
}
return res;
}
if ("loading" == document.readyState) {
document.addEventListener("DOMContentLoaded", function (){
s94.load.init(get_os())
})
}else {
s94.load.init(get_os());
}
s94_web.filename = typeof module === "object" && module.filename ? module.filename : s94.__stack(1)['file'];
s94_web.dom = function(selector) {
if(!(this instanceof s94_web.dom)) return new s94_web.dom(selector);
if(selector instanceof s94_web.dom) return selector;
Object.defineProperty(this, 'length', {value: 0,writable: true});
if(selector.nodeType || selector == global || selector == document) { //document或者window对象
this.push(selector);
} else if(typeof(selector) == "string") {
var doms = selector.indexOf('<')!=-1 ? s94_web.strtonodes(selector) : document.querySelectorAll(selector);
for(let i = 0; i < doms.length; i++) {
doms[i].nodeType == 1 && this.push(doms[i]);
}
} else if(typeof(selector) == "object" && selector.length) {
for(var i = 0; i < selector.length; i++) {
selector[i].nodeType == 1 && this.push(selector[i]);
}
}
return this;
}
s94_web.dom.extend = function(obj, options){
s94.extend(s94_web.dom.prototype, obj, options)
}
s94_web.dom.extend({
forEach: Array.prototype.forEach,
push: Array.prototype.push,
splice: Array.prototype.splice,
})
s94_web.dom.extend({
each: function(callback){
s94.each(this, callback)
return this;
},
eachloop: function(callback){
s94.eachloop(this, 'children', callback);
return this;
}
})
s94_web.loadCss = function (src){
if (!src || typeof src !== 'string') return;
src = s94.url(src).href;
let list = [];
document.querySelectorAll('link[rel="stylesheet"]').forEach(function (dom){
list.push(s94.url(dom.href).href)
})
if (~list.indexOf(src)) return;
let css = document.createElement('link');
css.rel = "stylesheet";
css.href = src;
document.querySelector('head').appendChild(css);
}
/**加载js
* @param {String|Array|Object} setup js地址(String|Array),或者包含地址(src)的配置参数
* @param {Function} callback 所有js加载完成后的回调函数,也可以使用返回的Promise
* @returns {Promise<unknown>}
*/
s94_web.loadJs = function(setup, callback){
let cache_list = s94_web.loadJs.list || {};
let callback_promise;
//数据整理
if (!setup) return;
if (typeof setup === 'string' || setup instanceof Array) setup = {src: setup};
var parent = setup.parent && setup.parent.nodeType==1 ? setup.parent : document.querySelector("head");
var srcs = typeof(setup.src)=="string"?[setup.src] : setup.src;
var callback_load = typeof(setup.load )=="function" ? setup.load : function(){};
var callback_error = typeof(setup.error )=="function" ? setup.error : function(){};
(new s94_web.dom('script[src]')).each(function(){
var k = s94.url(this.src);
if(!cache_list[k]) cache_list[k] = this;
})
var length = srcs.length;
var scriptNodes=[];
function callback_action(){
if (--length > 0) return;
typeof(callback)=="function" && callback.call(scriptNodes, scriptNodes);
callback_promise(scriptNodes);
}
for (var i = 0; i < srcs.length; i++) {
var k = s94.url(srcs[i]);
var row = cache_list[k];
if (row && !setup.refresh){
row.loading ? row.loadCallbacks.push(callback_action) : callback_action();
}else{
row = document.createElement("script");
row.type = setup.type || '';
row.loading = true;
row.loadCallbacks=[callback_action];
row.onload = function() {
callback_load.call(this, this);
delete this.loading;
for (; 0 < this.loadCallbacks.length;) {
this.loadCallbacks[0]();
this.loadCallbacks.splice(0,1);
}
}
row.onerror = function(e){
callback_error.call(this, this);
delete this.loading;
parent.removeChild(row);
}
row.src = srcs[i];
parent.appendChild(row);
}
scriptNodes.push(row);
cache_list[k] = row;
}
s94_web.loadJs.list = cache_list;
return new Promise(function (resolve){callback_promise=resolve;});
}
/*--------------------Document------------------*/
//hasClass、addClass、removeClass、toggleClass
s94_web.hasClass = function(dom,className){
return dom.classList ? dom.classList.contains(className) : (dom.className && dom.className.split(' ').indexOf(className)!=-1);
}
s94_web.addClass = function(dom,className){
if (s94_web.hasClass(dom,className)) return;
dom.classList ? dom.classList.add(className) : (dom.className += (dom.className?' ':''+className));
}
s94_web.removeClass = function(dom,className){
if (!s94_web.hasClass(dom,className)) return;
if (dom.classList) {
dom.classList.remove(className)
}else{
var classList = dom.className.split(' ');
classList.splice(classList.indexOf(className),1);
dom.className = classList.join(' ');
}
}
s94_web.toggleClass = function(dom,className){
dom.classList ? dom.classList.toggle(className) : (s94_web.hasClass(dom,className)?s94_web.removeClass(dom,className):s94_web.addClass(dom,className));
}
s94_web.dom.extend({
hasClass: function(className){
for (var i = 0; i < this.length; i++) {
if(s94_web.hasClass(this[i],className)) return true;
}
return false;
},
addClass: function(className){
this.forEach(function(dom){
s94_web.addClass(dom,className);
})
return this;
},
removeClass: function(className){
this.forEach(function(dom){
s94_web.removeClass(dom,className);
})
return this;
},
toggleClass: function(className){
this.forEach(function(dom){
s94_web.toggleClass(dom,className);
})
return this;
}
})
//text、html、attr、removeAttr、val、css
s94_web.dom.extend({
text:function(str){
if(typeof(str)=="undefined") return this.length ? this[0].innerText : false;
this.forEach(function(dom){
dom.innerText = str;
})
return this;
},
html: function(str){
if(typeof(str)=="undefined") return this.length ? this[0].innerHTML : false;
this.forEach(function(dom){
dom.innerHTML = str;
})
return this;
},
attr: function(name, value){
if(typeof(name)=="string" && typeof(value)=="undefined") return this.length ? this[0].getAttribute(name) : false;
this.forEach(function(dom){
if (typeof(name)=="string") {
dom.setAttribute(name,value);
} else{
for (var k in name) {
dom.setAttribute(k,name[k]);
}
}
})
return this;
},
removeAttr: function(name){
this.forEach(function(dom){
dom.removeAttribute(name);
})
return this;
},
val: function(value){
if(typeof(value)=="undefined") return this.length ? this[0].value : false;
this.forEach(function(dom){
dom.value = value;
})
return this;
},
css: function(name, value){
var obj = {};
if (typeof(name)=="string") {
if(name.indexOf(';')!==-1){
name.split(';').forEach(function(row){
if(!row) return;
var kv = row.split(':',2);
obj[s94.trim(kv[0])] = s94.trim(kv[1]);
})
}else if(typeof(value)=="undefined"){
return (this[0] instanceof Element) ? global.getComputedStyle(this[0]).getPropertyValue(name) : '';
}else{
obj[name] = value;
}
}else if(typeof(name)=="object"){
obj = name;
}
this.forEach(function(dom){
for (var k in obj) {
dom.style[k] = obj[k];
}
})
return this;
}
})
//eq、find、parent、parents
s94_web.dom.extend({
eq: function(index){
index = index < 0 ? (this.length+index) : index;
return new s94_web.dom(this[index] || []);
},
find: function(selector){
if(!selector) return false;
var doms = [];
this.forEach(function(dom){
s94.each(dom.querySelectorAll(selector),function(){doms.push(this)})
})
return new s94_web.dom(doms);
},
parent: function(selector){
var limt_nodes = [];
if(selector) s94.each(document.querySelectorAll(selector),function(){limt_nodes.push(this)});
var docs=[];
this.forEach(function(dom){
if(!dom.parentNode || dom.parentNode.nodeType !== 1) return;
if(docs.indexOf(dom.parentNode) == -1 && (!selector || limt_nodes.indexOf(dom.parentNode) !== -1)) docs.push(dom.parentNode);
})
return new s94_web.dom(docs);
},
parents: function(selector){
var limt_nodes = [];
if(selector) s94.each(document.querySelectorAll(selector),function(){limt_nodes.push(this)});
var docs=[];
this.forEach(function(dom){
while (dom.parentNode && dom.parentNode.nodeType == 1){
dom = dom.parentNode;
if(docs.indexOf(dom) == -1 && (!selector || limt_nodes.indexOf(dom) !== -1)) docs.push(dom);
}
})
return new s94_web.dom(docs);
}
})
//append、prepend、after、before、remove
//字符串转DOM节点
s94_web.strtonodes = function(str){
var istbody = !!str.match(/^<tbody[^>]*>([\s\S.]*)<\/tbody>$/);
var istr = !!str.match(/^<tr[^>]*>([\s\S.]*)<\/tr>$/);
var istd = !!str.match(/^<td[^>]*>([\s\S.]*)<\/td>$/);
var isth = !!str.match(/^<th[^>]*>([\s\S.]*)<\/th>$/);
var hasbody = /<body[\s>]/i.test(str);
var hashead = /<head/i.test(str);
var outer = document.createElement(istd||isth?'tr':(istr?'tbody':(istbody?'table': (hasbody?'html':'body') )));
outer.innerHTML = str;
var nodes = [];
for (var i = (hasbody && !hashead ? 1 : 0); i < outer.childNodes.length; i++) {
nodes.push(outer.childNodes[i]);
}
return nodes;
}
s94_web.dom.extend({
append: function(content){
if(typeof(content)=="undefined") return this;
this.forEach(function(dom){
if (dom.nodeType !== 1 && dom.nodeType !== 11 && dom.nodeType !== 9) return;
s94_web(content).each(function(){
dom.appendChild(typeof(content)=='string' ? this.cloneNode(true) : this);
})
})
return this;
},
prepend: function(content){
if(typeof(content)=="undefined") return this;
this.forEach(function(dom){
if (dom.nodeType !== 1 && dom.nodeType !== 11 && dom.nodeType !== 9) return;
var target = dom.firstChild;
s94_web(content).each(function(){
dom.insertBefore(typeof(content)=='string' ? this.cloneNode(true) : this, target);
})
})
return this;
},
after: function(content){
if(typeof(content)=="undefined") return this;
this.forEach(function(dom){
var parent = dom.parentNode;
if(!parent || (parent.nodeType !== 1 && parent.nodeType !== 9 && parent.nodeType !== 11) )return;
var target = dom.nextSibling;
s94_web(content).each(function(){
if(target){
parent.insertBefore(typeof(content)=='string' ? this.cloneNode(true) : this, target);
}else{
parent.appendChild(typeof(content)=='string' ? this.cloneNode(true) : this);
}
})
})
return this;
},
before: function(content){
if(typeof(content)=="undefined") return this;
this.forEach(function(dom){
var parent = dom.parentNode;
if(!parent || (parent.nodeType !== 1 && parent.nodeType !== 9 && parent.nodeType !== 11) )return;
s94_web(content).each(function(){
parent.insertBefore(typeof(content)=='string' ? this.cloneNode(true) : this, dom);
})
})
return this;
},
remove: function(selector){
var limt_nodes = [];
if(selector) s94.each(document.querySelectorAll(selector),function(){limt_nodes.push(this)});
this.forEach(function(dom){
if (!dom.parentNode) return;
if((!selector || limt_nodes.indexOf(dom) !== -1)) dom.parentNode.removeChild( dom );
})
return this;
}
})
//on、off、trigger
s94_web.dom.extend({
on: function(etype, callback, useCapture){
var k = etype+'EventCallbackList'+(useCapture?'Capture':'Bubbling')
this.forEach(function(dom){
dom[k] = dom[k] || [];
dom[k].push(callback);
dom.addEventListener(etype,callback,useCapture);
})
return this;
},
off: function(etype, useCapture){
var k = etype+'EventCallbackList'+(useCapture?'Capture':'Bubbling')
this.forEach(function(dom){
dom[k] = dom[k] || [];
if(dom[k]) for(;dom[k].length;){
dom.removeEventListener(etype,dom[k][0]);
dom[k].splice(0,1);
}
})
return this;
},
trigger: function(etype, extendData){
if (typeof(Event)=="function") {
var e = new Event(etype,{bubbles: true,cancelable: true,composed: true});
} else{
var e = document.createEvent('HTMLEvents');
e.initEvent(etype, true, true);
}
if(typeof(extendData)=='object') for (var k in extendData) {
if(typeof(e[k])=="undefined")e[k] = extendData[k];
}
this.forEach(function(dom){
if (dom.dispatchEvent) dom.dispatchEvent(e);
})
}
})
var extend_fns={};
['blur','focus','focusin','focusout','resize','scroll','click','dblclick','mousedown','mouseup','mousemove','mouseover','mouseout','mouseenter','mouseleave','change','select','submit','keydown','keypress','keyup','contextmenu'].forEach(function(name){
extend_fns[name] = function(callback){
return callback ? this.on(name,callback) : this.forEach(function(dom){
typeof(dom[name])=="function" && dom[name]();
})
}
});
s94_web.dom.extend(extend_fns);
//show、hide
s94_web.dom.extend({
show: function(time){
this.forEach(function(dom){
dom.hideTimeoutHander && clearTimeout(dom.hideTimeoutHander);
if(dom.style.display=='none'){
dom.style.display = dom.oldDisplay ? dom.oldDisplay : '';
}
if(s94_web(dom).css('display')=='none'){
dom.style.display = 'block';
}
if (time) {
dom.style.opacity = 0;
dom.style.transition = 'opacity '+(time/1000)+'s';
setTimeout(function(){dom.style.opacity=1;});
dom.showTimeoutHander = setTimeout(function(){dom.style.transition='';dom.style.opacity='';},time);
}
})
return this;
},
hide: function(time){
this.forEach(function(dom){
dom.showTimeoutHander && clearTimeout(dom.showTimeoutHander);
if(dom.style.display!='none') dom.oldDisplay = dom.style.display;
if (time) {
dom.style.opacity = 1;
dom.style.transition = 'opacity '+(time/1000)+'s';
setTimeout(function(){dom.style.opacity=0;});
dom.hideTimeoutHander = setTimeout(function(){dom.style.transition='';dom.style.opacity='';dom.style.display = 'none';},time);
}else{
dom.style.display = 'none';
}
})
return this;
}
})
//serializeArray、serialize
s94_web.dom.extend({
serializeArray: function(){
var arr = [];
this.forEach(function(dom){
var inputs = dom.querySelectorAll('input,select,textarea');
for (var i = 0; i < inputs.length; i++) {
if(!inputs[i].name) continue;
if(['submit','button'].indexOf(inputs[i].type)!==-1) continue;
if(['checkbox','radio'].indexOf(inputs[i].type)!==-1 && !inputs[i].checked) continue;
if(inputs[i].type=='file'){
for (var f = 0; f < inputs[i].files.length; f++) {
arr.push({name: inputs[i].name, value: inputs[i].files[f]});
}
}else{
arr.push({name: inputs[i].name, value: inputs[i].value});
}
}
})
return arr;
},
serialize: function(notencode){
var arr = this.serializeArray();
var param='';
arr.forEach(function(row){
param += '&'+row.name+'='+(notencode ? row.value : encodeURIComponent(row.value));
})
return param.substring(1);
}
})
//screenOffsetPage、domOffsetScreen、domOffsetPage、domOffsetParent、eventOffsetScreen、eventOffsetTarget、eventOffsetDom
/**
* 屏幕相对于页面的偏移
* @param {Object|Number} to 偏移跳转到坐标to,格式{x:像素,y:像素}
* @param {Object|Number} op [speed]动画执行速度(px/s)/[time]动画执行时间(毫秒),传入Number表示time
* @param {Function} callback 动画执行结束后执行的回调函数
*/
s94_web.screenOffsetPage = function(to, op, callback){
var res = {x: 0, y: 0};
res.x = document.documentElement.scrollLeft || document.body.scrollLeft || 0;
res.y = document.documentElement.scrollTop || document.body.scrollTop || 0;
//没有to参数,直接返回定位,不执行锚点跳转
if(typeof(to)=='undefined') return res;
function removeAction(){
s94_web.screenOffsetPage.th && (global.cancelAnimationFrame || global.webkitCancelAnimationFrame || global.mozCancelAnimationFrame || global.clearTimeout)(s94_web.screenOffsetPage.th)
}
removeAction();
if(typeof(op) == 'number') op = {time: op};
op = typeof(op)=='undefined'?{time: 1}:(typeof(op) == 'number'?{time: op}:op);
to = typeof(to) == 'number' ? {y:to} : to;
to.x = typeof(to.x) == 'undefined' ? res.x : to.x;
to.y = typeof(to.y) == 'undefined' ? res.y : to.y;
var start_time = (new Date()).getTime();
var time = op.time;
if(op.speed){
time = Math.max(Math.abs(to.x - res.x), Math.abs(to.y - res.y)) / op.speed * 1000;
}
function loop(){
var run_time = (new Date()).getTime() - start_time;
var bn = Math.min(run_time/time,1);
var now = {
x: res.x + ((to.x - res.x) * bn),
y: res.y + ((to.y - res.y) * bn)
};
document.body.scrollLeft = now.x;
document.body.scrollTop = now.y;
document.documentElement.scrollLeft = now.x;
document.documentElement.scrollTop = now.y;
if(bn >= 1) return typeof(callback)=="function" && callback();
s94_web.screenOffsetPage.th = requestAnimationFrame(loop);
}
setTimeout(loop, 1000 / 60);//此处需要延迟执行,否则可能会被系统默认还原
return res;
}
/**
* 元素相对于屏幕的偏移
* @param {Object} dom Document元素
*/
s94_web.domOffsetScreen = function(dom){
var r = dom.getBoundingClientRect();
return {x:r.left ,y:r.top};
}
/**
* 元素相对于页面的偏移【fixed定位的子元素相对于fixed定位元素】
* @param {Object} dom Document元素
*/
s94_web.domOffsetPage = function(dom){
//循环获取父级元素的offsetTop
var dos = s94_web.domOffsetScreen(dom);
var sop = s94_web.screenOffsetPage();
return {x: dos.x + sop.x, y: dos.y + sop.y};
}
/**
* 元素doc相对于父级元素parent的偏移
* @param {Object} dom Document元素
* @param {Object} parent 指定父元素【不填为第一个父级元素】
*/
s94_web.domOffsetParent = function(dom, parent){
parent = parent || dom.parentNode;
if(!parent) return {x: 0, y: 0};
var m = s94_web.domOffsetScreen(dom);
var p = s94_web.domOffsetScreen(parent);
return {x: m.x - p.x, y: m.y - p.y}
}
/**
* 获取事件触发定位,相对于屏幕
* @param {Event} e
*/
s94_web.eventOffsetScreen = function(e){
if (e instanceof TouchEvent){
if (e.type == 'touchend') return {x: e.changedTouches[0].clientX, y: e.changedTouches[0].clientY};
if (e.touches?.length) {
let points = [];
for (let i = 0; i < e.touches.length; i++) {
points.push({x: e.touches[i].clientX, y: e.touches[i].clientY})
}
return {x: points[0].s, y: points[0].y, points:points};
}
}else if (e instanceof MouseEvent){
return {x: e.clientX, y: e.clientY};
}
return {x:0,y:0};
}
/**
* 获取事件触发定位,相对于触发DOM节点
* @param {Event} e
*/
s94_web.eventOffsetTarget = function(e){
if (e instanceof TouchEvent){
let res = this.eventOffsetScreen(e);
let d_xy = this.domOffsetScreen(e.target);
if (res.points) res.points.forEach(function (p){
p.x = p.x - d_xy.x;
p.y = p.y - d_xy.y;
})
res.x = res.x - d_xy.x;
res.y = res.y - d_xy.y;
return res;
}else if (e instanceof MouseEvent){
return {x: e.offsetX, y: e.offsetY};
}
return {x:0,y:0};
}
/**
* 获取事件触发定位,相对于DOM节点
* @param {Object} dom 指定DOM节点元素【不填返回{x:0,y:0}】
* @param {Event} e window.event对象,默认为window.event
*/
s94_web.eventOffsetDom = function(dom,e){
if(typeof(dom)=='undefined') return {x:0,y:0};
if(dom===e.target) return this.eventOffsetTarget(e);
let res = this.eventOffsetScreen(e);
let d_xy = this.domOffsetScreen(dom);
if (res.points) res.points.forEach(function (p){
p.x = p.x - d_xy.x;
p.y = p.y - d_xy.y;
})
res.x = res.x - d_xy.x;
res.y = res.y - d_xy.y;
return res;
}
s94_web.dom.extend({
domOffsetPage : function(){
return s94_web.domOffsetPage(this[0]);
},
domOffsetScreen: function(){
return s94_web.domOffsetScreen(this[0]);
},
domOffsetParent: function(parent){
return s94_web.domOffsetParent(this[0], parent);
},
eventOffsetDom: function(){
return s94_web.eventOffsetDom(this[0]);
}
})
return s94_web
})(typeof globalThis !== 'undefined' ? globalThis :
typeof self !== "undefined" ? self :
typeof window !== "undefined" ? window :
typeof global !== "undefined" ? global : {});
export default s94_web;