3263 lines
110 KiB
Plaintext
3263 lines
110 KiB
Plaintext
(w => {
|
||
"use strict";
|
||
const OSSBase64 = require("./src/base64.js");
|
||
const icoConfig = require("./src/icoConfig.json");
|
||
// 缺省字段
|
||
const Alphabet = ["active", "local", "localhost", "pandorajs.com", "127.0.0.1", "192.168", "inherit", "提示", "错误", "警告"];
|
||
// 弹框集合
|
||
w.pdDialogs = [];
|
||
|
||
// 兼容处理&&基础方法
|
||
//requestAnimationFrame
|
||
if (!w.requestAnimationFrame) {
|
||
let lastTime, reqId;
|
||
w.requestAnimationFrame = callback => {
|
||
const currTime = new Date().getTime(),
|
||
timeToCall = Math.max(0, 16 - (currTime - lastTime)),
|
||
reqId = setTimeout(() => {
|
||
callback(currTime + timeToCall);
|
||
}, timeToCall);
|
||
lastTime = currTime + timeToCall;
|
||
return reqId;
|
||
};
|
||
|
||
w.cancelAnimationFrame = reqId => {
|
||
clearTimeout(reqId);
|
||
};
|
||
}
|
||
|
||
(function () {
|
||
//获取CSS变量
|
||
const getRoot = name => {
|
||
return w.getComputedStyle(document.documentElement).getPropertyValue(`--${name}`);
|
||
};
|
||
|
||
// 添加alert、confirm皮肤样式
|
||
let rootText = "";
|
||
if (!getRoot("alertTheme")) rootText += `/*alert背景*/--alertTheme:${Alphabet[6]};`;
|
||
if (!getRoot("alertBg")) rootText += `/*alert遮罩*/--alertBg:${Alphabet[6]};`;
|
||
if (!getRoot("alertFontSize")) rootText += "/*alert字体大小*/--alertFontSize:1rem;";
|
||
if (!getRoot("alertColor")) rootText += "/*alert字体颜色*/--alertColor:#000;";
|
||
|
||
if (!getRoot("confirmTheme")) rootText += `/*confirm背景*/--confirmTheme:#fff;`;
|
||
if (!getRoot("confirmBg")) rootText += `/*confirm遮罩*/--confirmBg:${Alphabet[6]};`;
|
||
if (!getRoot("confirmBtnBg")) rootText += "/*confirm按钮背景*/--confirmBtnBg:#fafafa;";
|
||
if (!getRoot("confirmFontSize")) rootText += "/*confirm字体大小*/--confirmFontSize:1rem;";
|
||
if (!getRoot("confirmColor")) rootText += "/*confirm字体颜色*/--confirmColor:#636363;";
|
||
if (!getRoot("confirmBtnColor")) rootText += "/*confirm按钮字体颜色*/--confirmBtnColor:#636363;";
|
||
if (!getRoot("confirmBtnBorder")) rootText += "/*confirm按钮边框颜色*/--confirmBtnBorder:#f1f1f1;";
|
||
|
||
const style = document.createElement("style");
|
||
style.innerText = `:root{${rootText}}`;
|
||
document.querySelector("head").appendChild(style);
|
||
|
||
//是否已经显示遮罩
|
||
let isMaskShow = !1;
|
||
const setGlobalCSS = (mask, maskBg, blur, plan) => {
|
||
mask.style.cssText = `
|
||
position:fixed;
|
||
inset:0;
|
||
top:0;
|
||
left:0;
|
||
right:0;
|
||
bottom:0;
|
||
z-index:999999999;
|
||
width:100%;
|
||
height:100%;
|
||
display:flex;
|
||
justify-content:center;
|
||
background:${Alphabet[6]};
|
||
background:${maskBg}`;
|
||
mask.className = "Pd_Mask";
|
||
blur.style.cssText = plan.style.cssText = `position:absolute;inset:0;top:0;left:0;right:0;bottom:0;`;
|
||
plan.style.cssText += `background:${Alphabet[6]};filter:blur(10px) saturate(2)`;
|
||
|
||
if (maskBg) plan.style.cssText += `background:rgba(255,255,255,.66)`;
|
||
};
|
||
|
||
//修改原生alert
|
||
if (w.resetAlert == undefined) {
|
||
w.resetAlert = !0;
|
||
}
|
||
if (w.resetAlert) {
|
||
w.alert = (content, speed = 800) => {
|
||
let timeout,
|
||
mask = document.createElement(`div`),
|
||
maskBg = !isMaskShow ? getRoot(`alertBg`) : null,
|
||
div = document.createElement(`div`),
|
||
msg = document.createElement(`p`),
|
||
blur = document.createElement(`div`),
|
||
plan = document.createElement(`div`),
|
||
Theme = getRoot(`alertTheme`),
|
||
fontSize = getRoot(`alertFontSize`),
|
||
color = getRoot(`alertColor`);
|
||
|
||
setGlobalCSS(mask, maskBg, blur, plan);
|
||
mask.style.cssText += `align-items:flex-end`;
|
||
div.style.cssText = `
|
||
background:${Alphabet[6]};
|
||
background:${Theme};
|
||
text-align:center;
|
||
color:${color};
|
||
font-size:${fontSize};
|
||
padding:.5em 1.5em;
|
||
line-height:1.3;
|
||
transition:opacity .4s ease-out;
|
||
margin-bottom:5vh;
|
||
box-shadow:0 8px 16px rgba(0,0,0,.25);
|
||
border-radius:6px;
|
||
position:relative;
|
||
overflow:hidden`;
|
||
div.id = "Pd_alert";
|
||
msg.style.cssText = `margin:0;position:relative`;
|
||
|
||
msg.innerText = content ? content + "" : "";
|
||
div.appendChild(blur);
|
||
div.appendChild(plan);
|
||
div.appendChild(msg);
|
||
mask.appendChild(div);
|
||
document.body.appendChild(mask);
|
||
|
||
mask.onclick = () => {
|
||
clearTimeout(timeout);
|
||
document.body.removeChild(mask);
|
||
mask = div = timeout = color = null;
|
||
};
|
||
|
||
clearTimeout(timeout);
|
||
timeout = setTimeout(() => {
|
||
div.style.opacity = 0;
|
||
div.addEventListener("transitionend", () => {
|
||
document.body.removeChild(mask);
|
||
mask = div = timeout = color = null;
|
||
});
|
||
}, speed);
|
||
};
|
||
}
|
||
|
||
//修改原生confirm
|
||
if (w.resetConfirm == undefined) {
|
||
w.resetConfirm = !0;
|
||
}
|
||
if (w.resetConfirm) {
|
||
w.confirm = config => {
|
||
let title = config.title || "",
|
||
content,
|
||
confirmText,
|
||
cancelText,
|
||
mask = document.createElement(`div`),
|
||
div = document.createElement(`div`),
|
||
blur = document.createElement(`div`),
|
||
plan = document.createElement(`div`),
|
||
titleCon = document.createElement(`h2`),
|
||
msg = document.createElement(`p`),
|
||
confirm = document.createElement(`button`),
|
||
cancel = document.createElement(`button`),
|
||
maskBg = !isMaskShow ? getRoot(`confirmBg`) : null,
|
||
btnBg = getRoot(`confirmBtnBg`),
|
||
Theme = getRoot(`confirmTheme`),
|
||
fontSize = getRoot(`confirmFontSize`),
|
||
color = getRoot(`confirmColor`),
|
||
btnColor = getRoot(`confirmBtnColor`),
|
||
btnBorder = getRoot(`confirmBtnBorder`);
|
||
const showConfirm = config.showConfirm == undefined ? !0 : config.showConfirm,
|
||
showCancel = config.showCancel == undefined ? !0 : config.showCancel;
|
||
confirmText = config.confirmText ? config.confirmText.toString() : "确认";
|
||
cancelText = config.cancelText ? config.cancelText.toString() : "取消";
|
||
|
||
setGlobalCSS(mask, maskBg, blur, plan);
|
||
mask.style.cssText += "align-items:center;";
|
||
div.style.cssText = `
|
||
background:${Alphabet[6]};
|
||
background:${Theme};
|
||
text-align:center;
|
||
color:${color};
|
||
font-size:${fontSize};
|
||
max-width:75vw;
|
||
min-width:20em;
|
||
box-shadow:0px 35px 35px -10px rgba(0,0,0,.33);
|
||
border-radius:10px;
|
||
position:relative;
|
||
white-space: break-spaces;
|
||
word-break: break-all;
|
||
overflow:hidden`;
|
||
div.id = "Pd_confirm";
|
||
|
||
titleCon.style.cssText = `position:relative;font-size:1.3em;min-height:1em;background:${btnBg};color:${btnColor};margin:0;padding:.5em 0`;
|
||
msg.style.cssText = `position:relative;border-top:1px solid ${btnBorder};width:100%;max-height:70vh;border-bottom:1px solid ${btnBorder};margin:0 auto;box-sizing:border-box;padding:2em 10%;line-height:1.4;overflow:auto`;
|
||
const buttonCSS = `position: relative;width:${
|
||
showConfirm && showCancel ? "50%" : "100%"
|
||
};font-size:1em;appearance:none;background:${btnBg};color:${btnColor};border:none;border-right:1px solid ${btnBorder};padding:1em 0;cursor:pointer;outline:none`;
|
||
confirm.style.cssText = cancel.style.cssText = buttonCSS;
|
||
|
||
const removeConfirm = () => {
|
||
document.body.removeChild(mask);
|
||
isMaskShow = !1;
|
||
};
|
||
|
||
if (!config.content) {
|
||
content = config + "";
|
||
} else {
|
||
content = config.content.toString();
|
||
}
|
||
|
||
titleCon.innerText = title ? title.toString() : "";
|
||
msg.innerText = content ? content.toString() : "";
|
||
div.appendChild(blur);
|
||
div.appendChild(plan);
|
||
div.appendChild(titleCon);
|
||
div.appendChild(msg);
|
||
|
||
if (showConfirm) {
|
||
confirm.innerText = confirmText;
|
||
div.appendChild(confirm);
|
||
}
|
||
if (showCancel) {
|
||
cancel.innerText = cancelText;
|
||
div.appendChild(cancel);
|
||
}
|
||
|
||
mask.appendChild(div);
|
||
document.body.appendChild(mask);
|
||
isMaskShow = !0;
|
||
|
||
return new Promise((ok, no) => {
|
||
if (showConfirm) {
|
||
confirm.onclick = () => {
|
||
removeConfirm();
|
||
ok();
|
||
};
|
||
}
|
||
|
||
if (showCancel) {
|
||
cancel.onclick = () => {
|
||
removeConfirm();
|
||
no();
|
||
};
|
||
}
|
||
});
|
||
};
|
||
}
|
||
|
||
//loading遮罩
|
||
const LoadingName = "Pd_loader";
|
||
let mask;
|
||
w.showLoading = (progress = null) => {
|
||
if (document.getElementById(LoadingName)) {
|
||
document.getElementById(LoadingName) && document.body.removeChild(document.getElementById(LoadingName));
|
||
}
|
||
mask = document.createElement("div");
|
||
const svg = new Image(),
|
||
em = document.createElement("em");
|
||
|
||
svg.src = icoConfig.load;
|
||
mask.id = LoadingName;
|
||
mask.style.cssText =
|
||
"font-size:1rem;width:100%;height:100%;position:fixed;z-index:999999999;inset:0;top:0;left:0;right:0;bottom:0;background:rgba(0,0,0,.65);display:flex;align-items:center;justify-content:center;flex-direction:column";
|
||
svg.style.width = svg.style.height = "3em";
|
||
mask.appendChild(svg);
|
||
|
||
if (progress !== null) {
|
||
em.style.cssText = "font-style:normal;font-size:1em;color:#fff;margin-top:.5em;";
|
||
em.innerText = progress;
|
||
mask.appendChild(em);
|
||
}
|
||
document.body.appendChild(mask);
|
||
};
|
||
w.hideLoading = () => {
|
||
if (document.getElementById(LoadingName)) {
|
||
document.body.removeChild(mask);
|
||
}
|
||
};
|
||
})();
|
||
|
||
//内置方法
|
||
class PandoraEX {
|
||
constructor(input = null) {
|
||
this.getInput = obj => {
|
||
if (Array.isArray(obj)) return obj;
|
||
if (["[object Window]", "[object HTMLDocument]"].includes(obj + "")) return w;
|
||
|
||
if (document.querySelectorAll(obj)) {
|
||
if (document.querySelectorAll(obj).length > 1) {
|
||
return document.querySelectorAll(obj);
|
||
} else {
|
||
if (obj) {
|
||
return document.querySelector(obj);
|
||
} else {
|
||
return null;
|
||
}
|
||
}
|
||
} else {
|
||
return console.error(`[${Alphabet[8]}] 未找到 ${obj}`);
|
||
}
|
||
};
|
||
this.get = this.getInput(input);
|
||
this.getLength = () => {
|
||
if (this.get) {
|
||
const { length } = this.get;
|
||
if (length) {
|
||
return length;
|
||
} else {
|
||
return 1;
|
||
}
|
||
}
|
||
};
|
||
this.length = this.getLength();
|
||
this.guid = () => {
|
||
const S4 = () => {
|
||
return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);
|
||
};
|
||
return `PandoraEX_${S4()}${S4()}-${S4()}-${S4()}-${S4()}-${S4()}${S4()}${S4()}`;
|
||
};
|
||
//生成GUID
|
||
this.pid = this.guid();
|
||
//默认参数赋值
|
||
this.extend = (config, options) => {
|
||
if (!options) {
|
||
options = config;
|
||
} else {
|
||
Object.keys(config).forEach(e => {
|
||
if (typeof options[e] === undefined || typeof options[e] === undefined + "") options[e] = config[e];
|
||
});
|
||
}
|
||
return options;
|
||
};
|
||
//选择指定下标元素
|
||
this.eq = index => {
|
||
try {
|
||
if (this.getInput(input).length) {
|
||
this.get = this.getInput(input)[index];
|
||
} else {
|
||
this.get = this.getInput(input);
|
||
}
|
||
} catch (err) {
|
||
console.error(`[${Alphabet[8]}] 未找到该下标`, err);
|
||
}
|
||
return this;
|
||
};
|
||
//选择子级元素
|
||
this.child = name => {
|
||
const ele = this.get;
|
||
try {
|
||
if (ele.querySelectorAll(name).length > 1) {
|
||
this.get = ele.querySelectorAll(name);
|
||
} else {
|
||
this.get = ele.querySelectorAll(name)[0];
|
||
}
|
||
} catch (err) {
|
||
console.error(`[${Alphabet[8]}] 未找到该子级`, err);
|
||
}
|
||
return this;
|
||
};
|
||
//查找子级元素
|
||
this.find = name => {
|
||
const ele = this.get;
|
||
try {
|
||
this.get = ele.querySelectorAll(name);
|
||
} catch (err) {
|
||
console.error(`[${Alphabet[8]}] 未找到该子级`, err);
|
||
}
|
||
return this;
|
||
};
|
||
//选择父级
|
||
this.parent = () => {
|
||
const ele = this.get;
|
||
try {
|
||
this.get = ele.parentElement;
|
||
} catch (err) {
|
||
console.error(`[${Alphabet[8]}] 未找到该父级`, err);
|
||
}
|
||
return this;
|
||
};
|
||
//选择其他同级元素
|
||
this.siblings = name => {
|
||
const ele = this.get,
|
||
parent = this.parent();
|
||
let siblingArr = [];
|
||
|
||
for (let e of parent.child(name).get) {
|
||
if (ele != e) siblingArr.push(e);
|
||
}
|
||
this.get = siblingArr;
|
||
return this;
|
||
};
|
||
//选择上一个同级元素
|
||
this.prev = () => {
|
||
const ele = this.get;
|
||
this.get = ele.previousElementSibling;
|
||
return this;
|
||
};
|
||
//选择下一个同级元素
|
||
this.next = () => {
|
||
const ele = this.get;
|
||
this.get = ele.nextElementSibling;
|
||
return this;
|
||
};
|
||
//选择第一个元素
|
||
this.first = () => {
|
||
return this.eq(0);
|
||
};
|
||
//选择最后一个元素
|
||
this.last = () => {
|
||
const ele = this.get;
|
||
if (ele.length) {
|
||
return this.eq(ele.length - 1);
|
||
} else {
|
||
return this.first();
|
||
}
|
||
};
|
||
//遍历元素集
|
||
this.each = fn => {
|
||
const ele = this.get;
|
||
if (ele.length) {
|
||
for (let i = 0; i < ele.length; i++) {
|
||
fn && fn(this.eq(i), i);
|
||
}
|
||
} else {
|
||
fn && fn(this.first(), 0);
|
||
}
|
||
return this;
|
||
};
|
||
//获取或修改样式
|
||
this.css = name => {
|
||
const ele = this.get;
|
||
let style = [];
|
||
style = name;
|
||
if (style) {
|
||
if (typeof style === "string") {
|
||
if (ele.length) {
|
||
return w.getComputedStyle(ele[0]).getPropertyValue(style);
|
||
} else {
|
||
return w.getComputedStyle(ele).getPropertyValue(style);
|
||
}
|
||
} else {
|
||
if (ele.length) {
|
||
for (let the of ele) {
|
||
Object.keys(style).forEach(e => {
|
||
the.style[e] = style[e];
|
||
});
|
||
}
|
||
} else {
|
||
Object.keys(style).forEach(e => {
|
||
ele.style[e] = style[e];
|
||
});
|
||
}
|
||
}
|
||
} else {
|
||
return w.getComputedStyle(ele).getPropertyValue("*");
|
||
}
|
||
};
|
||
//获取布局信息
|
||
this.offset = () => {
|
||
const ele = this.get;
|
||
if (ele.length) {
|
||
return ele[0].getBoundingClientRect();
|
||
} else {
|
||
return ele.getBoundingClientRect();
|
||
}
|
||
};
|
||
//获取或设置宽度
|
||
this.width = (width = null) => {
|
||
const ele = this.get;
|
||
if (width) {
|
||
if (ele.length) {
|
||
for (let the of ele) the.style.width = width;
|
||
} else {
|
||
ele.style.width = width;
|
||
}
|
||
} else {
|
||
if (ele.length) {
|
||
return ele[0].offsetWidth;
|
||
} else {
|
||
return ele.offsetWidth;
|
||
}
|
||
}
|
||
};
|
||
//获取或设置高度
|
||
this.height = (height = null) => {
|
||
const ele = this.get;
|
||
if (height) {
|
||
if (ele.length) {
|
||
for (let the of ele) the.style.height = height;
|
||
} else {
|
||
ele.style.height = height;
|
||
}
|
||
} else {
|
||
if (ele.length) {
|
||
return ele[0].offsetHeight;
|
||
} else {
|
||
return ele.offsetHeight;
|
||
}
|
||
}
|
||
};
|
||
//获取或插入文本
|
||
this.text = str => {
|
||
const ele = this.get;
|
||
if (str != undefined) {
|
||
if (ele.length) {
|
||
for (let the of ele) the.innerText = str + "";
|
||
} else {
|
||
ele.innerText = str + "";
|
||
}
|
||
} else {
|
||
if (ele.length) {
|
||
return ele[0].innerText;
|
||
} else {
|
||
return ele.innerText;
|
||
}
|
||
}
|
||
return this;
|
||
};
|
||
//获取或插入HTML
|
||
this.html = content => {
|
||
const ele = this.get;
|
||
if (content) {
|
||
this.empty();
|
||
if (ele.length) {
|
||
for (let the of ele) the.innerHTML = content;
|
||
} else {
|
||
ele.innerHTML = content;
|
||
}
|
||
} else {
|
||
if (ele.length) {
|
||
return ele[0].innerHTML;
|
||
} else {
|
||
return ele.innerHTML;
|
||
}
|
||
}
|
||
return this;
|
||
};
|
||
//获取或插入值
|
||
this.val = value => {
|
||
const ele = this.get;
|
||
if (ele.nodeName.toLowerCase() == "select") {
|
||
if (value != null && value != undefined) {
|
||
for (let the of ele) the.options[the.selectedIndex].value = value;
|
||
} else {
|
||
return ele.options[ele.selectedIndex].value;
|
||
}
|
||
} else {
|
||
if (ele.length) {
|
||
if (value != null && value != undefined) {
|
||
for (let the of ele) the.value = value;
|
||
} else {
|
||
return ele[0].value;
|
||
}
|
||
} else {
|
||
if (value != null && value != undefined) {
|
||
ele.value = value;
|
||
} else {
|
||
return ele.value;
|
||
}
|
||
}
|
||
}
|
||
return this;
|
||
};
|
||
//插入元素
|
||
this.prepend = target => {
|
||
const ele = this.get;
|
||
if (ele.length > 1) {
|
||
if (ele.nodeName.toLowerCase() == "select") {
|
||
if (typeof target == "object") {
|
||
ele.insertBefore(target, ele.firstChild);
|
||
} else {
|
||
const div = document.createElement("div");
|
||
div.innerHTML = target;
|
||
for (const dom of div.childNodes) ele.insertBefore(dom, ele.firstChild);
|
||
}
|
||
} else {
|
||
for (let the of ele) {
|
||
if (typeof target == "object") {
|
||
the.insertBefore(target, the.firstChild);
|
||
} else {
|
||
const div = document.createElement("div");
|
||
div.innerHTML = target;
|
||
for (const dom of div.childNodes) the.insertBefore(dom, the.firstChild);
|
||
}
|
||
}
|
||
}
|
||
} else {
|
||
if (typeof target == "object") {
|
||
ele.insertBefore(target, ele.firstChild);
|
||
} else {
|
||
const div = document.createElement("div");
|
||
div.innerHTML = target;
|
||
for (const dom of div.childNodes) ele.insertBefore(dom, ele.firstChild);
|
||
}
|
||
}
|
||
return this;
|
||
};
|
||
this.append = target => {
|
||
const ele = this.get;
|
||
|
||
if (ele.length > 1) {
|
||
if (ele.nodeName.toLowerCase() == "select") {
|
||
if (typeof target == "object") {
|
||
ele.appendChild(target);
|
||
} else {
|
||
const template = document.createElement("template");
|
||
template.innerHTML = target;
|
||
ele.appendChild(document.importNode(template.content, !0));
|
||
}
|
||
} else {
|
||
for (let the of ele) {
|
||
if (typeof target == "object") {
|
||
the.appendChild(target);
|
||
} else {
|
||
const template = document.createElement("template");
|
||
template.innerHTML = target;
|
||
the.appendChild(document.importNode(template.content, !0));
|
||
}
|
||
}
|
||
}
|
||
} else {
|
||
if (typeof target == "object") {
|
||
ele.appendChild(target);
|
||
} else {
|
||
const template = document.createElement("template");
|
||
template.innerHTML = target;
|
||
ele.appendChild(document.importNode(template.content, !0));
|
||
}
|
||
}
|
||
return this;
|
||
};
|
||
//清空容器
|
||
this.empty = () => {
|
||
const ele = this.get;
|
||
if (ele.length) {
|
||
for (let the of ele) {
|
||
while (the.firstChild) {
|
||
the.removeChild(the.firstChild);
|
||
}
|
||
}
|
||
} else {
|
||
while (ele.firstChild) {
|
||
ele.removeChild(ele.firstChild);
|
||
}
|
||
}
|
||
return this;
|
||
};
|
||
//移除元素
|
||
this.remove = () => {
|
||
const ele = this.get;
|
||
if (ele.length) {
|
||
for (let the of ele) {
|
||
try {
|
||
the.parentElement.removeChild(the);
|
||
} catch (err) {
|
||
console.error(`[${Alphabet[8]}] 未找到元素`, err);
|
||
}
|
||
}
|
||
} else {
|
||
try {
|
||
ele.parentElement.removeChild(ele);
|
||
} catch (err) {
|
||
console.error(`[${Alphabet[8]}] 未找到元素`, err);
|
||
}
|
||
}
|
||
return this;
|
||
};
|
||
//添加class
|
||
this.addClass = name => {
|
||
const ele = this.get,
|
||
addThat = the => {
|
||
const beforeClass = the.classList.value;
|
||
if (beforeClass) {
|
||
if (beforeClass.indexOf(name) < 0) the.className = `${beforeClass} ${name.trim()}`;
|
||
} else {
|
||
the.className = name.trim();
|
||
}
|
||
};
|
||
if (ele.length) {
|
||
for (let the of ele) addThat(the);
|
||
} else {
|
||
addThat(ele);
|
||
}
|
||
return this;
|
||
};
|
||
//移除class
|
||
this.removeClass = name => {
|
||
const ele = this.get,
|
||
removeThat = the => {
|
||
if (the.classList.value) {
|
||
let beforeClass = the.classList.value.split(" "),
|
||
afterClass;
|
||
beforeClass.map((cur, idx) => {
|
||
if (cur === name) beforeClass.splice(idx, 1);
|
||
});
|
||
afterClass = beforeClass.join(" ");
|
||
the.className = afterClass;
|
||
}
|
||
};
|
||
|
||
if (ele.length) {
|
||
for (let the of ele) removeThat(the);
|
||
} else {
|
||
removeThat(ele);
|
||
}
|
||
return this;
|
||
};
|
||
//是否拥有class名
|
||
this.hasClass = name => {
|
||
const ele = this.get,
|
||
classlist = ele.classList.value.indexOf(" ") > -1 ? ele.classList.value.split(" ") : ele.classList.value;
|
||
if (classlist.indexOf(name) > -1) {
|
||
return !0;
|
||
} else {
|
||
return !1;
|
||
}
|
||
};
|
||
//添加属性
|
||
this.attr = (inject, val) => {
|
||
const ele = this.get;
|
||
if (ele.length) {
|
||
if (typeof inject == "object") {
|
||
for (let the of ele) {
|
||
for (let keyName in inject) the.setAttribute(keyName, inject[keyName]);
|
||
}
|
||
return this;
|
||
} else {
|
||
if (val) {
|
||
for (let the of ele) the.setAttribute(inject, val);
|
||
return this;
|
||
} else {
|
||
return ele[0].getAttribute(inject);
|
||
}
|
||
}
|
||
} else {
|
||
if (typeof inject == "object") {
|
||
for (let keyName in inject) ele.setAttribute(keyName, inject[keyName]);
|
||
return this;
|
||
} else {
|
||
if (val) {
|
||
ele.setAttribute(inject, val);
|
||
return this;
|
||
} else {
|
||
return ele.getAttribute(inject);
|
||
}
|
||
}
|
||
}
|
||
};
|
||
//移除属性
|
||
this.removeAttr = name => {
|
||
const ele = this.get;
|
||
if (ele.length) {
|
||
for (let the of ele) the.removeAttribute(name);
|
||
} else {
|
||
ele.removeAttribute(name);
|
||
}
|
||
return this;
|
||
};
|
||
//绑定事件
|
||
this.bind = (eventName, fn, options = {}, bool = !1) => {
|
||
const ele = this.get;
|
||
const capture = options.capture || !1,
|
||
once = options.once || !1,
|
||
passive = options.passive || !1;
|
||
|
||
if (ele.length) {
|
||
let eleIndex = 0;
|
||
for (let the of ele) {
|
||
the.addEventListener(eventName, fn, { capture, once, passive }, bool);
|
||
the.index = eleIndex++;
|
||
the.eventList = [];
|
||
the.eventList.push({ name: eventName, callback: fn });
|
||
}
|
||
} else {
|
||
ele.addEventListener(eventName, fn, { capture, once, passive }, bool);
|
||
ele.eventList = [];
|
||
ele.eventList.push({ name: eventName, callback: fn });
|
||
}
|
||
return this;
|
||
};
|
||
//解绑事件
|
||
this.unbind = eventName => {
|
||
const ele = this.get;
|
||
if (ele.length) {
|
||
for (let the of ele) {
|
||
if (the.eventList) {
|
||
the.eventList.map((e, i) => {
|
||
if (e.name === eventName) {
|
||
the.removeEventListener(eventName, e.callback);
|
||
the.eventList.splice(i, 1);
|
||
}
|
||
});
|
||
}
|
||
}
|
||
} else {
|
||
if (ele.eventList) {
|
||
ele.eventList.map((e, i) => {
|
||
if (e.name === eventName) {
|
||
ele.removeEventListener(eventName, e.callback);
|
||
ele.eventList.splice(i, 1);
|
||
}
|
||
});
|
||
}
|
||
}
|
||
return this;
|
||
};
|
||
//获取焦点
|
||
this.focus = () => {
|
||
const ele = this.get;
|
||
if (ele.length) {
|
||
for (let the of ele) {
|
||
the.focus();
|
||
}
|
||
} else {
|
||
ele.focus();
|
||
}
|
||
return this;
|
||
};
|
||
//移除焦点
|
||
this.blur = () => {
|
||
const ele = this.get;
|
||
if (ele.length) {
|
||
for (let the of ele) {
|
||
the.blur();
|
||
}
|
||
} else {
|
||
ele.blur();
|
||
}
|
||
return this;
|
||
};
|
||
//点击&触摸点击事件
|
||
this.click = fn => {
|
||
const ele = this.get;
|
||
if (ele.length) {
|
||
for (let a = 0; a < ele.length; a++) {
|
||
if (w.ontouchstart) {
|
||
ele[a].ontouchstart = () => {
|
||
this.get = ele[a];
|
||
fn(this, a);
|
||
};
|
||
} else {
|
||
ele[a].onclick = () => {
|
||
this.get = ele[a];
|
||
fn(this, a);
|
||
};
|
||
}
|
||
}
|
||
} else {
|
||
if (w.ontouchstart) {
|
||
ele.ontouchstart = () => {
|
||
fn(this, null);
|
||
};
|
||
} else {
|
||
ele.onclick = () => {
|
||
fn(this, null);
|
||
};
|
||
}
|
||
}
|
||
return this;
|
||
};
|
||
//双击事件
|
||
this.dblclick = fn => {
|
||
const ele = this.get;
|
||
if (ele.length) {
|
||
for (let a = 0; a < ele.length; a++) {
|
||
ele[a].ondblclick = () => {
|
||
this.get = ele[a];
|
||
fn(this, a);
|
||
};
|
||
}
|
||
} else {
|
||
ele.ondblclick = () => {
|
||
fn(this, null);
|
||
};
|
||
}
|
||
return this;
|
||
};
|
||
//主动触发事件
|
||
this.trigger = eventName => {
|
||
const ele = this.get;
|
||
const event = new Event(eventName);
|
||
if (ele.length) {
|
||
for (let the of ele) {
|
||
the.dispatchEvent(event);
|
||
}
|
||
} else {
|
||
ele.dispatchEvent(event);
|
||
}
|
||
return this;
|
||
};
|
||
//长按事件
|
||
this.taping = (fn, cb) => {
|
||
const ele = this.get;
|
||
let infiniteFrame;
|
||
const infiniteFn = () => {
|
||
fn && fn(ele);
|
||
infiniteFrame = requestAnimationFrame(infiniteFn);
|
||
};
|
||
|
||
if (w.ontouchstart) {
|
||
ele.ontouchstart = event => {
|
||
event.preventDefault();
|
||
cancelAnimationFrame(infiniteFn);
|
||
infiniteFn();
|
||
};
|
||
ele.ontouchend = () => {
|
||
cb && cb(ele);
|
||
cancelAnimationFrame(infiniteFrame);
|
||
};
|
||
} else {
|
||
ele.onmousedown = () => {
|
||
cancelAnimationFrame(infiniteFn);
|
||
infiniteFn();
|
||
};
|
||
ele.onmouseup = () => {
|
||
cb && cb(ele);
|
||
cancelAnimationFrame(infiniteFrame);
|
||
};
|
||
}
|
||
|
||
return this;
|
||
};
|
||
//显示
|
||
this.show = callback => {
|
||
this.attr(`beforeHide`) ? this.css({ display: this.attr(`beforeHide`) }) : this.css({ display: "block" });
|
||
callback && setTimeout(callback);
|
||
return this;
|
||
};
|
||
//隐藏
|
||
this.hide = callback => {
|
||
if (!this.attr(`beforeHide`)) this.attr("beforeHide", this.css(`display`) == "none" ? "block" : this.css(`display`));
|
||
this.css({ display: "none" });
|
||
callback && setTimeout(callback);
|
||
return this;
|
||
};
|
||
// 淡入
|
||
this.fadeIn = (speed = "fast", callback) => {
|
||
const that = this;
|
||
let opacity = 0,
|
||
req;
|
||
|
||
const fade = () => {
|
||
if (opacity < 100) {
|
||
switch (speed) {
|
||
case "fast":
|
||
opacity += 5;
|
||
break;
|
||
case "slow":
|
||
opacity++;
|
||
break;
|
||
default:
|
||
opacity += speed;
|
||
break;
|
||
}
|
||
req = requestAnimationFrame(fade);
|
||
} else {
|
||
callback && callback();
|
||
cancelAnimationFrame(req);
|
||
}
|
||
that.css({ opacity: opacity / 100 });
|
||
};
|
||
that.show(() => {
|
||
that.css({ opacity: 0 });
|
||
fade();
|
||
});
|
||
|
||
return this;
|
||
};
|
||
// 淡出
|
||
this.fadeOut = (speed = "fast", callback) => {
|
||
const that = this;
|
||
let opacity = 100,
|
||
req;
|
||
|
||
const fade = () => {
|
||
if (opacity > 0) {
|
||
switch (speed) {
|
||
case "fast":
|
||
opacity -= 5;
|
||
break;
|
||
case "slow":
|
||
opacity--;
|
||
break;
|
||
default:
|
||
opacity -= speed;
|
||
break;
|
||
}
|
||
req = requestAnimationFrame(fade);
|
||
} else {
|
||
that.hide(() => {
|
||
callback && callback();
|
||
cancelAnimationFrame(req);
|
||
});
|
||
}
|
||
that.css({ opacity: opacity / 100 });
|
||
};
|
||
fade();
|
||
return this;
|
||
};
|
||
//ajax
|
||
this.ajax = options => {
|
||
let config = {
|
||
//接口地址(类型:字符串)
|
||
url: null,
|
||
//请求类型(类型:字符串;可选参数:post、get)
|
||
type: "get",
|
||
//是否同步请求(类型:布尔)
|
||
async: !1,
|
||
//设置请求头(类型:对象)
|
||
headers: { "Content-type": "application/x-www-form-urlencoded" },
|
||
//发送数据类型(类型:字符串;可选参数:json、form)
|
||
dataType: "json",
|
||
//返回体类型(类型:字符串)
|
||
responseType: "json",
|
||
//发送数据(类型:json或form;格式必须和发送数据类型保持一致)
|
||
data: null,
|
||
//加载中回调方法(类型:方法)
|
||
progress: null,
|
||
//成功回调方法(类型:方法)
|
||
success: null,
|
||
//失败回调方法(类型:方法)
|
||
error: null,
|
||
};
|
||
config = this.extend(config, options);
|
||
const http = new XMLHttpRequest(),
|
||
{ url, type, async, headers, dataType, data, progress, success, error, responseType } = config;
|
||
let params;
|
||
if (dataType == "json") {
|
||
if (data)
|
||
params = Object.keys(data)
|
||
.map(key => {
|
||
return `${encodeURIComponent(key)}=${encodeURIComponent(data[key])}`;
|
||
})
|
||
.join(`&`);
|
||
} else {
|
||
params = data;
|
||
}
|
||
|
||
if (async) {
|
||
http.responseType = responseType;
|
||
}
|
||
|
||
try {
|
||
// 监听加载中
|
||
http.upload.onprogress = event => {
|
||
if (event.lengthComputable) {
|
||
progress && progress(Math.floor((event.loaded / event.total) * 100));
|
||
}
|
||
};
|
||
} catch (e) {}
|
||
|
||
// 向全局添加取消请求方法
|
||
w.cancelAjax = () => {
|
||
http.abort();
|
||
};
|
||
|
||
return new Promise((resolve, reject) => {
|
||
http.onreadystatechange = () => {
|
||
if (http.status === 200 && http.readyState === 4 && http.response) {
|
||
if (async) {
|
||
resolve(http.response);
|
||
success && success(http.response);
|
||
} else {
|
||
resolve(JSON.parse(http.response));
|
||
success && success(JSON.parse(http.response));
|
||
}
|
||
}
|
||
};
|
||
|
||
http.onerror = err => {
|
||
reject(err);
|
||
error && error(err);
|
||
};
|
||
|
||
http.open(type.toUpperCase(), url, async);
|
||
|
||
if (headers) {
|
||
// 如果data是formdata类型,不设置请求头
|
||
if (data && data.constructor !== FormData) {
|
||
for (let keys in headers) http.setRequestHeader(keys, headers[keys]);
|
||
}
|
||
}
|
||
|
||
http.send(params);
|
||
});
|
||
};
|
||
//fetch
|
||
this.fetch = options => {
|
||
let config = {
|
||
//接口地址(类型:字符串)
|
||
url: null,
|
||
//设置请求头(类型:对象)
|
||
headers: { "Content-type": "application/x-www-form-urlencoded" },
|
||
//请求类型(类型:字符串;可选参数:post、get)
|
||
type: "get",
|
||
//发送数据(类型:JSON)
|
||
data: null,
|
||
//返回数据格式化(类型:方法)
|
||
returnData(res) {
|
||
return res.json();
|
||
},
|
||
};
|
||
config = this.extend(config, options);
|
||
const { url, data, headers, type, returnData } = config;
|
||
|
||
return new Promise((resolve, reject) => {
|
||
if (data) {
|
||
fetch(url, { body: JSON.stringify(data), headers, method: type.toLocaleUpperCase() })
|
||
.then(res => {
|
||
if (res.ok) {
|
||
return returnData(res);
|
||
} else {
|
||
console.error(`[${Alphabet[8]}] 请求错误`, res);
|
||
}
|
||
})
|
||
.then(resolve)
|
||
.catch(reject);
|
||
} else {
|
||
fetch(url, { headers, method: type.toLocaleUpperCase() })
|
||
.then(res => {
|
||
if (res.ok) {
|
||
return returnData(res);
|
||
} else {
|
||
console.error(`[${Alphabet[8]}] 请求错误`, res);
|
||
}
|
||
})
|
||
.then(resolve)
|
||
.catch(reject);
|
||
}
|
||
});
|
||
};
|
||
//表单序列化
|
||
this.serialize = () => {
|
||
const ele = this.get;
|
||
let obj = {};
|
||
for (let e of ele.querySelectorAll(`*`)) {
|
||
if (e.getAttribute(`name`)) {
|
||
const keyName = e.getAttribute(`name`);
|
||
|
||
if (keyName) {
|
||
switch (e.type) {
|
||
case "radio":
|
||
if (e.checked) obj[keyName] = e.value;
|
||
break;
|
||
case "checkbox":
|
||
if (e.checked) {
|
||
obj[keyName] = e.value;
|
||
} else {
|
||
obj[keyName] = !1;
|
||
}
|
||
break;
|
||
default:
|
||
obj[keyName] = e.value;
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
return obj;
|
||
};
|
||
//NEW设置表单
|
||
this.setForm = (obj = null) => {
|
||
if (obj) {
|
||
const ele = this.get,
|
||
formChilds = ele.querySelectorAll(`[name]`);
|
||
|
||
formChilds.forEach(e => {
|
||
const keyName = e.getAttribute(`name`);
|
||
if (obj[keyName]) {
|
||
if (e.readOnly) return console.error(`[${Alphabet[8]}] 该元素为只读,无法设置值`);
|
||
switch (e.type) {
|
||
case "radio":
|
||
if (e.value == obj[keyName]) {
|
||
e.checked = !0;
|
||
} else {
|
||
e.checked = !1;
|
||
}
|
||
break;
|
||
case "checkbox":
|
||
if (obj[keyName]) e.checked = !0;
|
||
break;
|
||
case "file":
|
||
e.files = obj[keyName];
|
||
break;
|
||
case "select":
|
||
e.value = obj[keyName];
|
||
break;
|
||
default:
|
||
e.value = obj[keyName];
|
||
break;
|
||
}
|
||
}
|
||
});
|
||
} else {
|
||
console.error(`[${Alphabet[8]}] 无可设置的表单数据`);
|
||
}
|
||
return this;
|
||
};
|
||
//渲染变量
|
||
this.globalData = {};
|
||
//设置渲染变量
|
||
this.setData = obj => {
|
||
return new Promise((success, fail) => {
|
||
for (let key in obj) {
|
||
try {
|
||
this.globalData[key] = obj[key];
|
||
} catch (err) {
|
||
console.error(`[${Alphabet[8]} - Mush] 变量修改失败`, err);
|
||
fail(err);
|
||
}
|
||
}
|
||
success();
|
||
});
|
||
};
|
||
//获取渲染变量
|
||
this.getData = key => {
|
||
if (this.globalData[key]) {
|
||
return this.globalData[key];
|
||
} else {
|
||
console.error(`[${Alphabet[8]} - Mush] 获取的变量不存在!`);
|
||
return null;
|
||
}
|
||
};
|
||
//模板渲染
|
||
this.template = (route, container) => {
|
||
return new Promise((success, fail) => {
|
||
const temp = (() => {
|
||
let cur;
|
||
const template = document.querySelectorAll(`template`);
|
||
for (let a = 0; a < template.length; a++) {
|
||
if (template[a].getAttribute(`route`) == route) cur = template[a];
|
||
}
|
||
return cur;
|
||
})();
|
||
|
||
if (temp) {
|
||
this.empty();
|
||
let url = temp.getAttribute("src");
|
||
const that = this;
|
||
|
||
if (url) {
|
||
that
|
||
.fetch({
|
||
url,
|
||
headers: { "Content-type": "text/html" },
|
||
returnData(res) {
|
||
return res.text();
|
||
},
|
||
})
|
||
.then(res => {
|
||
const node = document.createElement(`template`);
|
||
node.innerHTML = res;
|
||
if (node.content.querySelectorAll(`link`)) {
|
||
let linkArr = [];
|
||
for (let link of node.content.querySelectorAll(`link`)) {
|
||
linkArr.push(
|
||
that.fetch({
|
||
url: link.href,
|
||
headers: { "Content-type": "text/html" },
|
||
returnData(res) {
|
||
return res.text();
|
||
},
|
||
})
|
||
);
|
||
node.content.removeChild(link);
|
||
}
|
||
Promise.all(linkArr).then(res => {
|
||
res.map(the => {
|
||
const style = document.createElement("style");
|
||
style.innerHTML = the;
|
||
node.content.appendChild(style);
|
||
});
|
||
insertHTML();
|
||
});
|
||
} else {
|
||
insertHTML();
|
||
}
|
||
|
||
//插入HTML
|
||
function insertHTML() {
|
||
container.appendChild(document.importNode(node.content, !0));
|
||
for (let script of node.content.querySelectorAll(`script`)) {
|
||
if (script.getAttribute("src")) {
|
||
that
|
||
.fetch({
|
||
url: script.src,
|
||
headers: { "Content-type": "text/html" },
|
||
returnData(res) {
|
||
return res.text();
|
||
},
|
||
})
|
||
.then(res => {
|
||
eval(res);
|
||
});
|
||
} else {
|
||
eval(script.innerHTML);
|
||
}
|
||
}
|
||
success();
|
||
}
|
||
})
|
||
.catch(err => {
|
||
console.error(`[${Alphabet[8]} - Router] 不存在以下路由:${err.target.responseURL}`);
|
||
fail(`${route}`);
|
||
});
|
||
} else {
|
||
container.appendChild(document.importNode(temp.content, !0));
|
||
success();
|
||
}
|
||
} else {
|
||
console.error(`[${Alphabet[8]} - Router] 不存在以下路由:${route}`);
|
||
fail(`${route}`);
|
||
}
|
||
});
|
||
};
|
||
//获取url参数并转换成对象
|
||
this.getParams = () => {
|
||
const url = location.href.split(`?`);
|
||
if (location.href.indexOf(`?`) > -1) {
|
||
let obj = {};
|
||
if (url[1].split(`&`)) {
|
||
const params = url[1].split(`&`);
|
||
params.map(v => {
|
||
obj[v.split(`=`)[0]] = v.split(`=`)[1];
|
||
});
|
||
} else {
|
||
obj[url[1].split(`=`)[0]] = obj[url[1].split(`=`)[1]];
|
||
}
|
||
return obj;
|
||
} else {
|
||
return null;
|
||
}
|
||
};
|
||
// HASH改变
|
||
this.hashChange = (callback, routes) => {
|
||
const getRoutePath = () => {
|
||
if (location.hash.indexOf(`#`) > -1) {
|
||
return location.hash.match(/#(\S*)\?/) === null ? location.hash.match(/#(\S*)/).input.replace(`#`, ``) : location.hash.match(/#(\S*)\?/).input.replace(`#`, ``);
|
||
} else {
|
||
return !1;
|
||
}
|
||
};
|
||
const routePath = getRoutePath() || routes[0].path;
|
||
callback(routePath);
|
||
};
|
||
// 数组相关方法
|
||
this.Array = {
|
||
// 原始数组
|
||
originals: this.get,
|
||
// 随机打乱数组
|
||
Random() {
|
||
let originals = this.originals;
|
||
for (let i = 0; i < originals.length; i++) originals[i] = originals[i];
|
||
originals.sort(() => {
|
||
return 0.5 - Math.random();
|
||
});
|
||
return originals;
|
||
},
|
||
// 判断是否存在重复
|
||
hasRepeat() {
|
||
const originals = this.originals;
|
||
let hash = {};
|
||
for (let i in originals) {
|
||
if (hash[originals[i]]) {
|
||
return !0;
|
||
}
|
||
hash[originals[i]] = !0;
|
||
}
|
||
return !1;
|
||
},
|
||
// 数组求和
|
||
Sum() {
|
||
const arr = this.originals;
|
||
let s = 0;
|
||
for (let i = arr.length - 1; i >= 0; i--) s += arr[i];
|
||
return s;
|
||
},
|
||
};
|
||
}
|
||
}
|
||
//拓展方法
|
||
const PandoraJs = SuperClass => {
|
||
return class extends SuperClass {
|
||
constructor(obj) {
|
||
super(obj);
|
||
}
|
||
//Mustache渲染
|
||
Mush(options) {
|
||
let config = {
|
||
//渲染数据(类型:对象)
|
||
data: null,
|
||
//生命周期-首次渲染完成(类型:方法;返回初始渲染数据)
|
||
Init: null,
|
||
// 生命周期-每次更新渲染完成(类型:方法;返回最新渲染数据)
|
||
Update: null,
|
||
};
|
||
config = this.extend(config, options);
|
||
let Html = this.html(),
|
||
bHtml = Html,
|
||
matchValue;
|
||
const that = this,
|
||
{ data, Init, Update } = config,
|
||
pattern = new RegExp("{{.*?}}", "g"),
|
||
patterns = new RegExp("{{.*?}}");
|
||
|
||
// 重构渲染数据
|
||
const getObj = res => {
|
||
let newObj = {};
|
||
for (let keyName of Object.keys(res)) newObj[keyName] = res[keyName];
|
||
return newObj;
|
||
};
|
||
|
||
// 获取所有MUSH变量
|
||
const getMush = () => {
|
||
let r = [];
|
||
Html.match(pattern).forEach((e, index) => {
|
||
r[index] = e.split(`{{`)[1].split(`}}`)[0];
|
||
});
|
||
return r;
|
||
};
|
||
matchValue = getMush();
|
||
|
||
//渲染html
|
||
const renderHtml = () => {
|
||
return new Promise(next => {
|
||
Html = bHtml;
|
||
for (let value of matchValue) {
|
||
for (let keyName in data) {
|
||
if (value === keyName) {
|
||
Html = Html.replace(patterns, data[value] + "" || "");
|
||
}
|
||
}
|
||
}
|
||
that.html(Html);
|
||
next();
|
||
});
|
||
};
|
||
|
||
// 返回所有唯一变量
|
||
const unique = array => {
|
||
let r = [];
|
||
for (let i = 0, l = array.length; i < l; i++) {
|
||
for (let j = i + 1; j < l; j++) {
|
||
if (array[i] == array[j]) {
|
||
j == ++i;
|
||
}
|
||
}
|
||
r.push(array[i]);
|
||
}
|
||
return r;
|
||
};
|
||
|
||
//遍历变量是否被动态修改
|
||
unique(matchValue).forEach(e => {
|
||
Object.defineProperty(that.globalData, e, {
|
||
set(value) {
|
||
data[e] = value;
|
||
renderHtml()
|
||
.then(() => {
|
||
Update && Update(getObj(that.globalData));
|
||
})
|
||
.catch(err => {
|
||
console.error(`[${Alphabet[8]} - Mush] 变量更新失败`, err);
|
||
});
|
||
},
|
||
get() {
|
||
return data[e];
|
||
},
|
||
enumerable: !0,
|
||
});
|
||
});
|
||
|
||
renderHtml()
|
||
.then(() => {
|
||
Init && Init(getObj(that.globalData));
|
||
})
|
||
.catch(err => {
|
||
console.error(`[${Alphabet[8]} - Mush] 初始渲染失败`, err);
|
||
});
|
||
|
||
return this;
|
||
}
|
||
//静态路由
|
||
Router(options) {
|
||
let config = {
|
||
// 路由路径集合(类型:数组)
|
||
routes: null,
|
||
};
|
||
config = this.extend(config, options);
|
||
const that = this,
|
||
{ routes } = config;
|
||
|
||
// 初始化路由
|
||
const initRoute = () => {
|
||
that
|
||
.template(routes[0].path.split("?")[0], that.get)
|
||
.then(() => {
|
||
that.currentRoute = routes[0].path.split("?")[0];
|
||
try {
|
||
routes[0].callback && routes[0].callback(that.getParams() ? that.getParams() : {});
|
||
} catch (err) {
|
||
routes[0].error && routes[0].error(err);
|
||
console.error(`[${Alphabet[8]} - Router]`, err);
|
||
}
|
||
})
|
||
.catch(err => {
|
||
routes[0].error && routes[0].error(err);
|
||
console.error(`[${Alphabet[8]} - Router]`, err);
|
||
});
|
||
};
|
||
|
||
// 遍历路由路径
|
||
const eachRoutes = path => {
|
||
if (path) {
|
||
if (JSON.stringify(routes).indexOf(path.split("?")[0]) < 0) {
|
||
console.error(`[${Alphabet[8]} - Router] ${path.split("?")[0]} 不存在于routes`);
|
||
} else {
|
||
try {
|
||
routes.forEach(e => {
|
||
if (path.split("?")[0] == e.path) {
|
||
that
|
||
.template(path.split("?")[0], that.get)
|
||
.then(() => {
|
||
that.go(path);
|
||
that.currentRoute = path;
|
||
try {
|
||
e.callback && e.callback(that.getParams() ? that.getParams() : {});
|
||
} catch (err) {
|
||
e.error && e.error(err);
|
||
console.error(`[${Alphabet[8]} - Router]`, err);
|
||
}
|
||
})
|
||
.catch(err => {
|
||
e.error && e.error(err);
|
||
console.error(`[${Alphabet[8]} - Router]`, err);
|
||
});
|
||
}
|
||
});
|
||
} catch (err) {
|
||
console.error(`[${Alphabet[8]} - Router]`, err);
|
||
}
|
||
}
|
||
} else {
|
||
console.error(`[${Alphabet[8]} - Router] 不存在任何路由`);
|
||
}
|
||
};
|
||
|
||
// 返回上一路由
|
||
that.back = () => {
|
||
setTimeout(() => {
|
||
w.history.back();
|
||
});
|
||
};
|
||
|
||
// 路由导航
|
||
that.go = path => {
|
||
setTimeout(() => {
|
||
w.location.href = `#${path}`;
|
||
});
|
||
};
|
||
|
||
// 路由重定向
|
||
that.direct = path => {
|
||
setTimeout(() => {
|
||
w.location.replace(`#${path}`);
|
||
});
|
||
};
|
||
|
||
// 路由重载
|
||
that.reload = () => {
|
||
eachRoutes(w.location.hash.split("#")[1]);
|
||
};
|
||
|
||
// 初始化
|
||
if (routes) {
|
||
if (w.location.hash.indexOf("#") < 0) {
|
||
initRoute();
|
||
} else {
|
||
if (w.location.hash.split("#")[1] == routes[0].path) {
|
||
initRoute();
|
||
} else {
|
||
eachRoutes(w.location.hash.split("#")[1]);
|
||
}
|
||
}
|
||
|
||
w.onhashchange = () => {
|
||
that.hashChange(eachRoutes, routes);
|
||
};
|
||
} else {
|
||
return console.error(`[${Alphabet[8]} - Router] 不存在任何路由!`);
|
||
}
|
||
return this;
|
||
}
|
||
//轮播切换
|
||
Switcher(options) {
|
||
let config = {
|
||
//过渡速度/秒(类型:数字)
|
||
Speed: 1,
|
||
//动画曲线(类型:字符串;参考css3动画曲线)
|
||
Curve: "ease",
|
||
//切换效果(类型:字符串;可选参数:slider、fade)
|
||
Effect: "slider",
|
||
//方向(类型:字符串;可选参数:horizontal、vertical)
|
||
Direction: "horizontal",
|
||
//惯性回弹(类型:布尔)
|
||
Inertia: !0,
|
||
//滑动比例(类型:数字)
|
||
Distance: 3,
|
||
//自动切换间隔/秒(类型:数字;为0时不自动切换)
|
||
AutoSpeed: 0,
|
||
//分页器(类型:布尔)
|
||
Pagination: !1,
|
||
//悬浮停止(类型:布尔)
|
||
Hover: !1,
|
||
//滚轮滚动(类型:布尔)
|
||
Scroll: !1,
|
||
//初始坐标(类型:数字)
|
||
InitPage: 0,
|
||
//循环(类型:布尔)
|
||
Loop: !1,
|
||
//切换状态变化(类型:方法)
|
||
onChange: null,
|
||
//是否窗口大小改变时自动调整(类型:布尔)
|
||
AutoResize: !1,
|
||
};
|
||
config = this.extend(config, options);
|
||
const { Speed, Curve, Effect, Direction, Inertia, Distance, AutoSpeed, Pagination, Hover, Scroll, InitPage, Loop, onChange, AutoResize } = config,
|
||
childEle = this.get,
|
||
parentEle = childEle[0].parentElement,
|
||
total = childEle.length,
|
||
transitionend = () => {
|
||
if (isScrolling) {
|
||
isScrolling = !1;
|
||
parentEle.removeEventListener("transitionend", transitionend);
|
||
}
|
||
};
|
||
let currentPage = InitPage,
|
||
childW = childEle[0].offsetWidth,
|
||
childH = childEle[0].offsetHeight,
|
||
AutoTimeout,
|
||
isScrolling = !1,
|
||
isFristTime = !0;
|
||
|
||
//切换
|
||
const Swiper = (moveTo = null) => {
|
||
if (typeof moveTo == "number") currentPage = moveTo;
|
||
Pager(currentPage);
|
||
if (!isFristTime) {
|
||
onChange && onChange(currentPage);
|
||
}
|
||
switch (Effect) {
|
||
case "fade":
|
||
for (let cur of childEle) {
|
||
if (cur.className.indexOf("active") > -1) {
|
||
cur.style.opacity = 1;
|
||
cur.style.zIndex = 2;
|
||
} else {
|
||
cur.style.opacity = 0;
|
||
cur.style.zIndex = 1;
|
||
}
|
||
}
|
||
break;
|
||
default:
|
||
switch (Direction) {
|
||
case "vertical":
|
||
parentEle.style.transform = `translate3d(0,${-1 * (childH * currentPage)}px,0)`;
|
||
break;
|
||
case "horizontal":
|
||
default:
|
||
parentEle.style.transform = `translate3d(${-1 * (childW * currentPage)}px,0,0)`;
|
||
break;
|
||
}
|
||
break;
|
||
}
|
||
if (Loop) {
|
||
parentEle.addEventListener("transitionend", transitionend);
|
||
} else {
|
||
if (currentPage === 0 || currentPage === total - 1) {
|
||
transitionend();
|
||
} else {
|
||
parentEle.addEventListener("transitionend", transitionend);
|
||
}
|
||
}
|
||
};
|
||
|
||
//分页器
|
||
const Pager = current => {
|
||
for (let e of childEle) e.className = e.className.replace(Alphabet[0], "").trim();
|
||
if (childEle[currentPage].className) {
|
||
childEle[currentPage].className += ` ${Alphabet[0]}`;
|
||
} else {
|
||
childEle[currentPage].className += Alphabet[0];
|
||
}
|
||
if (Pagination) {
|
||
parentEle.parentElement.querySelector(`.Pd-pagination`) && parentEle.parentElement.removeChild(parentEle.parentElement.querySelector(`.Pd-pagination`));
|
||
const pager = document.createElement("div");
|
||
pager.className = "Pd-pagination";
|
||
|
||
for (let a = 0; a < total; a++) {
|
||
const pageChild = document.createElement("a"),
|
||
textNode = childEle[a].getAttribute(`data-title`) ? document.createTextNode(childEle[a].getAttribute(`data-title`)) : document.createTextNode(a);
|
||
pageChild.setAttribute("href", "javascript:void 0");
|
||
if (a === current) pageChild.className = Alphabet[0];
|
||
pageChild.appendChild(textNode);
|
||
pager.appendChild(pageChild);
|
||
}
|
||
parentEle.parentElement.insertBefore(pager, parentEle.nextElementSibling);
|
||
|
||
for (let a = 0; a < parentEle.parentElement.querySelectorAll(`.Pd-pagination a`).length; a++) {
|
||
const e = parentEle.parentElement.querySelectorAll(`.Pd-pagination a`)[a],
|
||
idx = a;
|
||
e.onclick = () => {
|
||
currentPage = idx;
|
||
Swiper();
|
||
};
|
||
}
|
||
}
|
||
};
|
||
|
||
//上一个
|
||
const Prev = () => {
|
||
isFristTime = !1;
|
||
if (currentPage < total && currentPage > 0) {
|
||
currentPage--;
|
||
} else if (currentPage === 0 && Loop) {
|
||
currentPage = total - 1;
|
||
} else {
|
||
isScrolling = !1;
|
||
}
|
||
Swiper();
|
||
};
|
||
|
||
//下一个
|
||
const Next = () => {
|
||
isFristTime = !1;
|
||
if (currentPage < total - 1) {
|
||
currentPage++;
|
||
} else if (currentPage === total - 1 && Loop) {
|
||
currentPage = 0;
|
||
} else {
|
||
currentPage = total - 1;
|
||
}
|
||
Swiper();
|
||
};
|
||
|
||
let startX, startY, endX, endY, curX, curY;
|
||
//方法:滑动开始
|
||
const touchStart = event => {
|
||
clearTimeout(AutoTimeout);
|
||
cancelAnimationFrame(AutoPlayFrame);
|
||
const { pageX, pageY } = event.changedTouches[0];
|
||
const { left, top } = parentEle.parentElement.getBoundingClientRect();
|
||
|
||
switch (config.Direction) {
|
||
case "vertical":
|
||
startY = pageY - top;
|
||
break;
|
||
case "horizontal":
|
||
default:
|
||
startX = pageX - left;
|
||
break;
|
||
}
|
||
parentEle.style.transition = null;
|
||
};
|
||
|
||
//方法:滑动中
|
||
const touchMove = event => {
|
||
const { pageX, pageY } = event.changedTouches[0],
|
||
{ left, top } = parentEle.parentElement.getBoundingClientRect();
|
||
curX = pageX - left;
|
||
curY = pageY - top;
|
||
|
||
switch (Effect) {
|
||
case "fade":
|
||
for (let cur of childEle) cur.style.transition = `opacity ${Speed}s linear`;
|
||
break;
|
||
default:
|
||
switch (Direction) {
|
||
case "vertical":
|
||
if (startY > curY) {
|
||
if (currentPage != total - 1) parentEle.style.transform = `translate3d(0,${-1 * (startY - curY + childH * currentPage)}px,0)`;
|
||
} else {
|
||
if (currentPage != 0) parentEle.style.transform = `translate3d(0,${-1 * (childH * currentPage) + Math.abs(curY - startY)}px,0)`;
|
||
}
|
||
break;
|
||
case "horizontal":
|
||
default:
|
||
if (startX > curX) {
|
||
parentEle.style.transform = `translate3d(${-1 * (startX - curX + childW * currentPage)}px,0,0)`;
|
||
} else {
|
||
parentEle.style.transform = `translate3d(${-1 * (childW * currentPage) + Math.abs(curX - startX)}px,0,0)`;
|
||
}
|
||
break;
|
||
}
|
||
break;
|
||
}
|
||
};
|
||
|
||
//方法:滑动结束
|
||
const touchEnd = event => {
|
||
clearTimeout(AutoTimeout);
|
||
AutoPlay();
|
||
parentEle.style.transition = `transform ${Speed}s ${Curve}`;
|
||
const { pageX, pageY } = event.changedTouches[0],
|
||
{ left, top } = parentEle.parentElement.getBoundingClientRect();
|
||
|
||
switch (Direction) {
|
||
case "vertical":
|
||
endY = pageY - top;
|
||
switch (Effect) {
|
||
case "fade":
|
||
if (startY - endY > childH / config.Distance && currentPage === total - 1) {
|
||
currentPage = 0;
|
||
} else if (startY - endY > childH / config.Distance && currentPage < total - 1) {
|
||
Next();
|
||
} else if (endY - startY > childH / config.Distance) {
|
||
Prev();
|
||
}
|
||
for (let cur of childEle) {
|
||
cur.style.transition = `opacity ${config.Speed}s ${config.Curve}`;
|
||
cur.style.opacity = 0;
|
||
cur.style.zIndex = 1;
|
||
}
|
||
childEle[currentPage].style.opacity = 1;
|
||
childEle[currentPage].style.zIndex = 2;
|
||
Swiper();
|
||
break;
|
||
default:
|
||
if (startY - endY > childH / config.Distance && currentPage < total - 1) Next();
|
||
if (endY - startY > childH / config.Distance) Prev();
|
||
parentEle.style.transform = `translate3d(0,${-1 * (childH * currentPage)}px,0)`;
|
||
break;
|
||
}
|
||
break;
|
||
case "horizontal":
|
||
default:
|
||
endX = pageX - left;
|
||
switch (Effect) {
|
||
case "fade":
|
||
if (startX - endX > childW / Distance && currentPage === total - 1) {
|
||
currentPage = 0;
|
||
} else if (startX - endX > childW / Distance && currentPage < total - 1) {
|
||
Next();
|
||
} else if (endX - startX > childW / Distance) {
|
||
Prev();
|
||
}
|
||
for (let cur of childEle) {
|
||
cur.style.transition = `opacity ${Speed}s ${Curve}`;
|
||
cur.style.opacity = 0;
|
||
cur.style.zIndex = 1;
|
||
}
|
||
childEle[currentPage].style.opacity = 1;
|
||
childEle[currentPage].style.zIndex = 2;
|
||
Swiper();
|
||
break;
|
||
default:
|
||
if (startX - endX > childW / Distance && currentPage < total - 1) Next();
|
||
if (endX - startX > childW / Distance) Prev();
|
||
parentEle.style.transform = `translate3d(${-1 * (childW * currentPage)}px,0,0)`;
|
||
break;
|
||
}
|
||
break;
|
||
}
|
||
};
|
||
|
||
//方法:滚动中
|
||
const scrollMove = event => {
|
||
event.preventDefault();
|
||
if (event.deltaY > 20 && !isScrolling) {
|
||
isScrolling = !0;
|
||
Next();
|
||
}
|
||
if (event.deltaY < -20 && !isScrolling) {
|
||
isScrolling = !0;
|
||
Prev();
|
||
}
|
||
};
|
||
|
||
//自动播放
|
||
let AutoPlayFrame;
|
||
const AutoPlay = () => {
|
||
if (AutoSpeed) {
|
||
AutoTimeout = setTimeout(() => {
|
||
Next();
|
||
clearTimeout(AutoTimeout);
|
||
AutoPlayFrame = requestAnimationFrame(AutoPlay);
|
||
}, AutoSpeed * 1000);
|
||
}
|
||
};
|
||
|
||
//初始化
|
||
function Init() {
|
||
const { width, height } = parentEle.parentElement.getBoundingClientRect();
|
||
childW = width;
|
||
childH = height;
|
||
currentPage = InitPage;
|
||
return new Promise(next => {
|
||
switch (Effect) {
|
||
case "fade":
|
||
for (let cur of childEle) {
|
||
cur.style.transition = `opacity ${Speed}s ${Curve}`;
|
||
cur.style.position = "absolute";
|
||
}
|
||
parentEle.style.width = `${width}px`;
|
||
parentEle.style.height = `${height}px`;
|
||
break;
|
||
default:
|
||
switch (Direction) {
|
||
case "vertical":
|
||
parentEle.style.width = `${width}px`;
|
||
parentEle.style.height = `${height * total}px`;
|
||
parentEle.style.flexDirection = "column";
|
||
parentEle.style.cssText += "touch-action: pan-x";
|
||
break;
|
||
case "horizontal":
|
||
default:
|
||
parentEle.style.width = `${width * total}px`;
|
||
parentEle.style.height = `${height}px`;
|
||
parentEle.style.flexDirection = "row";
|
||
parentEle.style.cssText += "touch-action: pan-y";
|
||
break;
|
||
}
|
||
parentEle.style.display = "flex";
|
||
parentEle.style.transition = `transform ${Speed}s ${Curve}`;
|
||
break;
|
||
}
|
||
|
||
//移除事件
|
||
Swiper(InitPage);
|
||
AutoPlay();
|
||
Inertia && parentEle.removeEventListener("touchmove", touchMove);
|
||
Scroll && parentEle.removeEventListener("mousewheel", scrollMove);
|
||
parentEle.removeEventListener("touchstart", touchStart);
|
||
parentEle.removeEventListener("touchend", touchEnd);
|
||
|
||
//添加事件
|
||
Inertia && parentEle.addEventListener("touchmove", touchMove);
|
||
Scroll && parentEle.addEventListener("mousewheel", scrollMove);
|
||
parentEle.addEventListener("touchstart", touchStart);
|
||
parentEle.addEventListener("touchend", touchEnd);
|
||
if (Hover) {
|
||
parentEle.addEventListener("mouseover", () => {
|
||
clearTimeout(AutoTimeout);
|
||
cancelAnimationFrame(AutoPlayFrame);
|
||
});
|
||
parentEle.addEventListener("mouseout", AutoPlay);
|
||
}
|
||
next();
|
||
});
|
||
}
|
||
|
||
this.prev = Prev;
|
||
this.next = Next;
|
||
this.direct = index => {
|
||
isFristTime = !1;
|
||
Swiper(index);
|
||
};
|
||
this.disable = () => {
|
||
Inertia && parentEle.removeEventListener("touchmove", touchMove);
|
||
Scroll && parentEle.removeEventListener("mousewheel", scrollMove);
|
||
parentEle.removeEventListener("touchstart", touchStart);
|
||
parentEle.removeEventListener("touchend", touchEnd);
|
||
clearTimeout(AutoTimeout);
|
||
cancelAnimationFrame(AutoPlayFrame);
|
||
};
|
||
this.enable = () => {
|
||
//添加事件
|
||
Inertia && parentEle.addEventListener("touchmove", touchMove);
|
||
Scroll && parentEle.addEventListener("mousewheel", scrollMove);
|
||
parentEle.addEventListener("touchstart", touchStart);
|
||
parentEle.addEventListener("touchend", touchEnd);
|
||
if (Hover) {
|
||
parentEle.addEventListener("mouseover", () => {
|
||
clearTimeout(AutoTimeout);
|
||
cancelAnimationFrame(AutoPlayFrame);
|
||
});
|
||
parentEle.addEventListener("mouseout", AutoPlay);
|
||
}
|
||
if (AutoSpeed) {
|
||
AutoTimeout = setTimeout(() => {
|
||
Next();
|
||
clearTimeout(AutoTimeout);
|
||
AutoPlayFrame = requestAnimationFrame(AutoPlay);
|
||
}, AutoSpeed * 1000);
|
||
}
|
||
};
|
||
Init();
|
||
if (AutoResize) {
|
||
let isResizing = !1;
|
||
let resizeTimer;
|
||
w.onresize = () => {
|
||
clearTimeout(resizeTimer);
|
||
resizeTimer = null;
|
||
if (!isResizing) {
|
||
isResizing = !0;
|
||
resizeTimer = setTimeout(() => {
|
||
Init();
|
||
isResizing = !1;
|
||
}, 300);
|
||
}
|
||
};
|
||
}
|
||
return this;
|
||
}
|
||
//页面&字体自适应
|
||
AutoSize(options) {
|
||
let config = {
|
||
//固定尺寸(类型:字符串)
|
||
PageSize: "device-width",
|
||
//初始缩放(类型:数字)
|
||
InitScale: 1,
|
||
//最小缩放(类型:数字)
|
||
MinScale: 1,
|
||
//最大缩放(类型:数字)
|
||
MaxScale: 1,
|
||
//DPI缩放(类型:数字;默认:window.devicePixelRatio)
|
||
Ratio: null,
|
||
//窗口变化重新计算(类型:布尔)
|
||
Resize: !0,
|
||
//是否缩放字体大小(类型:布尔)
|
||
ScaleFont: !0,
|
||
};
|
||
config = this.extend(config, options);
|
||
const meta = document.createElement(`meta`),
|
||
{ PageSize, InitScale, MinScale, MaxScale, Resize, ScaleFont } = config;
|
||
let Ratio = config.Ratio || w.devicePixelRatio;
|
||
meta.setAttribute("name", "viewport");
|
||
|
||
if (typeof PageSize !== "number") {
|
||
meta.setAttribute("content", `width=${PageSize},initial-scale=${InitScale},minimum-scale=${MinScale},maximum-scale=${MaxScale},user-scalable=no,viewport-fit=cover`);
|
||
} else {
|
||
meta.setAttribute("content", `width=${PageSize},user-scalable=no,viewport-fit=cover`);
|
||
}
|
||
|
||
if (document.querySelector("meta[name='viewport']")) {
|
||
document.querySelector("meta[name='viewport']").remove();
|
||
}
|
||
|
||
document.head.appendChild(meta);
|
||
|
||
if (ScaleFont) {
|
||
//根据屏幕尺寸设置根元素字体大小
|
||
const SetSize = () => {
|
||
const { clientWidth: width, clientHeight: height } = document.documentElement;
|
||
document.documentElement.style.fontSize = `${(Math.min(width, height) / 10) * Ratio}px`;
|
||
};
|
||
SetSize();
|
||
if (Resize) w.onresize = SetSize;
|
||
}
|
||
|
||
return this;
|
||
}
|
||
//自定义弹框
|
||
Dialog(options) {
|
||
let config = {
|
||
//是否显示遮罩
|
||
mask: !0,
|
||
//遮罩颜色(类型:字符串)
|
||
maskColor: "rgba(0,0,0,.85)",
|
||
//点击遮罩退出(类型:布尔)
|
||
maskOut: !0,
|
||
//过渡速度/毫秒(类型:数字)
|
||
Speed: 180,
|
||
//过渡曲线(类型:字符串;参考CSS3可用曲线)
|
||
Curve: "ease-out",
|
||
//进出方式(类型:字符串;none:无、zoom:缩放、top:从屏幕上方出现、bottom:从屏幕下方出现)
|
||
Direction: "zoom",
|
||
//进入事件(类型:方法)
|
||
In: null,
|
||
//退出事件(类型:方法)
|
||
Out: null,
|
||
//确认事件
|
||
Confirm: {
|
||
//确定按钮(类型:字符串)
|
||
btn: null,
|
||
//回调(类型:方法;返回类型:对象)
|
||
callback: null,
|
||
},
|
||
//取消事件
|
||
Cancel: {
|
||
//取消按钮(类型:字符串)
|
||
btn: null,
|
||
//回调(类型:方法;返回类型:对象)
|
||
callback: null,
|
||
},
|
||
};
|
||
config = this.extend(config, options);
|
||
const masker = document.createElement(`div`),
|
||
parent = this.get.parentElement,
|
||
{ mask, maskColor, maskOut, Speed, Curve, Direction, In, Out, Confirm, Cancel } = config;
|
||
masker.className = "Pd-Mask";
|
||
const confirmBtn = Confirm.btn ? new PandoraEX(Confirm.btn) : null,
|
||
cancelBtn = Cancel.btn ? new PandoraEX(Cancel.btn) : null;
|
||
|
||
if (Direction !== "none") this.css({ transition: `all ${Speed}ms ${Curve}` });
|
||
|
||
//关闭弹框
|
||
const closeDialog = () => {
|
||
return new Promise(next => {
|
||
if (this.css("display") == "block" || this.css("display") == "flex") {
|
||
Effect(`out`);
|
||
if (Direction === "none") {
|
||
try {
|
||
mask && parent.removeChild(masker);
|
||
} catch (err) {
|
||
console.error(`[${Alphabet[8]} - Dialog]`, err);
|
||
}
|
||
this.css({ display: "none" });
|
||
next();
|
||
} else {
|
||
this.bind("transitionend", () => {
|
||
try {
|
||
mask && parent.removeChild(masker);
|
||
} catch (err) {
|
||
console.error(`[${Alphabet[8]} - Dialog]`, err);
|
||
}
|
||
this.css({ display: "none" });
|
||
this.unbind("transitionend");
|
||
next();
|
||
});
|
||
}
|
||
} else {
|
||
next();
|
||
}
|
||
Confirm.btn && confirmBtn.unbind(`click`);
|
||
Cancel.btn && cancelBtn.unbind(`click`);
|
||
w.onresize = null;
|
||
});
|
||
};
|
||
|
||
//进入和退出效果
|
||
const Effect = where => {
|
||
if (mask && where === "in") {
|
||
parent.insertBefore(masker, this.get.nextElementSibling);
|
||
document.querySelector(`.Pd-Mask`).style.cssText = `width:100vw;height:100vh;background:${maskColor};position:fixed;inset:0;top:0;left:0;right:0;bottom:0;z-index:998;`;
|
||
}
|
||
|
||
switch (where) {
|
||
case "in":
|
||
this.css({ display: "block" });
|
||
switch (Direction) {
|
||
case "none":
|
||
this.css({ display: "block" });
|
||
break;
|
||
case "top":
|
||
this.css({ transform: "translate3d(0,-100%,0)" });
|
||
break;
|
||
case "bottom":
|
||
this.css({ transform: "translate3d(0,100%,0)" });
|
||
break;
|
||
case "zoom":
|
||
this.css({ transform: "translate3d(0,0,0) scale(0)" });
|
||
break;
|
||
}
|
||
In && In();
|
||
break;
|
||
case "out":
|
||
switch (Direction) {
|
||
case "none":
|
||
this.css({ display: "none" });
|
||
break;
|
||
case "top":
|
||
this.css({ transform: "translate3d(0,-100%,0)" });
|
||
break;
|
||
case "bottom":
|
||
this.css({ transform: "translate3d(0,100%,0)" });
|
||
break;
|
||
case "zoom":
|
||
this.css({ transform: "translate3d(0,0,0) scale(0)" });
|
||
break;
|
||
}
|
||
Out && Out();
|
||
break;
|
||
}
|
||
};
|
||
|
||
//打开弹框
|
||
const openDialog = param => {
|
||
this.unbind("transitionend");
|
||
for (let a of w.pdDialogs) {
|
||
if (a != this) a.close();
|
||
}
|
||
Effect(`in`);
|
||
|
||
return new Promise(next => {
|
||
const calcDialog = () => {
|
||
const top = parseInt(this.css(`height`)) / 2,
|
||
left = parseInt(this.css(`width`)) / 2;
|
||
switch (Direction) {
|
||
case "none":
|
||
this.css({ position: "fixed", top: `calc(50% - ${top}px)`, left: `calc(50% - ${left}px)`, "z-index": 999 });
|
||
break;
|
||
case "top":
|
||
this.css({ position: "fixed", top: 0, left: `calc(50% - ${left}px)`, "z-index": 999, transform: "translate3d(0,0,0) scale(1)" });
|
||
break;
|
||
case "bottom":
|
||
this.css({ position: "fixed", bottom: 0, left: `calc(50% - ${left}px)`, "z-index": 999, transform: "translate3d(0,0,0) scale(1)" });
|
||
break;
|
||
case "zoom":
|
||
default:
|
||
this.css({ position: "fixed", top: `calc(50% - ${top}px)`, left: `calc(50% - ${left}px)`, "z-index": 999, transform: "translate3d(0,0,0) scale(1)" });
|
||
break;
|
||
}
|
||
};
|
||
calcDialog();
|
||
w.onresize = () => {
|
||
this.bind("transitionend", calcDialog);
|
||
};
|
||
|
||
//遮罩被点击
|
||
if (mask && maskOut) masker.onclick = closeDialog;
|
||
const { close } = this;
|
||
//确认按钮被点击
|
||
Confirm.btn &&
|
||
confirmBtn.bind("click", () => {
|
||
Confirm.callback({ param: param || null, close });
|
||
});
|
||
//取消按钮被点击
|
||
Cancel.btn &&
|
||
cancelBtn.bind("click", () => {
|
||
Cancel.callback({ param: param || null, close });
|
||
});
|
||
next();
|
||
});
|
||
};
|
||
|
||
this.close = closeDialog;
|
||
this.open = openDialog;
|
||
|
||
w.pdDialogs.push(this);
|
||
return this;
|
||
}
|
||
//图片预加载
|
||
ImgLoader(options) {
|
||
let config = {
|
||
//渐进式(类型:布尔)
|
||
lazy: !0,
|
||
//加载中(类型:方法;返回类型:数字)
|
||
loading: null,
|
||
//加载完成(类型:方法)
|
||
callback: null,
|
||
//加载错误(类型:方法)
|
||
error(err) {
|
||
console.error(`[${Alphabet[8]} - ImgLoader] 资源加载错误!\n${err}`);
|
||
alert("资源加载错误!");
|
||
},
|
||
};
|
||
config = this.extend(config, options);
|
||
const { lazy, loading, callback, error } = config;
|
||
let ImgArr = [],
|
||
total = 0,
|
||
cur = 0,
|
||
step = 0,
|
||
floatNum = 0;
|
||
|
||
// 类型检查
|
||
const typeCheck = str => {
|
||
if (str.indexOf(`url`) > -1 && str != "none" && str.indexOf(`data:`) < 0 && str.indexOf(`blob:`) < 0) {
|
||
return !0;
|
||
} else {
|
||
return !1;
|
||
}
|
||
};
|
||
|
||
// 仅容器内获取
|
||
const onlyContainer = (ele, callout) => {
|
||
const pattern = new RegExp('".*?"', "g"),
|
||
pattern2 = new RegExp(/'.*?'/, "g"),
|
||
pattern3 = new RegExp(/\(.*?\)/, "g");
|
||
|
||
for (let e of ele.querySelectorAll("*")) {
|
||
if (e.nodeName.toLowerCase() == "img") {
|
||
if (e.src) {
|
||
ImgArr.push(e.src);
|
||
}
|
||
}
|
||
const getBg = w.getComputedStyle(e).getPropertyValue(`background-image`);
|
||
if (typeCheck(getBg)) {
|
||
const url1 = getBg.match(pattern),
|
||
url2 = getBg.match(pattern2),
|
||
url3 = getBg.match(pattern3);
|
||
|
||
url1 && ImgArr.push(url1[0].toString().replace(/"/g, ""));
|
||
url2 && ImgArr.push(url2[0].toString().replace(/'/g, ""));
|
||
|
||
if (url3) {
|
||
let src = url3[0].toString().replace(/\(/, "").replace(/\)/, "");
|
||
if (src.match(pattern)) src = src.match(pattern)[0].toString().replace(/"/g, "");
|
||
if (src.match(pattern2)) src = src.match(pattern2)[0].toString().replace(/'/g, "");
|
||
ImgArr.push(src);
|
||
}
|
||
}
|
||
}
|
||
callout();
|
||
};
|
||
|
||
// 全局获取
|
||
const allResources = callout => {
|
||
const pattern1 = new RegExp(`background-image: url(.*?)*`, "g"),
|
||
pattern2 = new RegExp(`background: url(.*?)*`, "g");
|
||
|
||
// 截取背景图
|
||
const getThat = (type, str) => {
|
||
let src;
|
||
switch (type) {
|
||
case 1:
|
||
src = str.split(`background-image: url(`)[1].split(`)`)[0];
|
||
break;
|
||
case 2:
|
||
src = str.split(`background: url(`)[1].split(`)`)[0];
|
||
break;
|
||
}
|
||
if (src.indexOf(`"`) > -1) return src.replace(/"/g, ``);
|
||
if (src.indexOf(`'`) > -1) return src.replace(/'/g, ``);
|
||
return src;
|
||
};
|
||
|
||
document.querySelectorAll("link").forEach(css => {
|
||
if (css.getAttribute("rel") == "stylesheet") {
|
||
this.ajax({
|
||
url: css.getAttribute("href"),
|
||
responseType: "text",
|
||
}).then(str => {
|
||
if (str.match(pattern1)) {
|
||
for (let a of str.match(pattern1)) {
|
||
typeCheck(a) && ImgArr.push(getThat(1, a));
|
||
}
|
||
}
|
||
if (str.match(pattern2)) {
|
||
for (let a of str.match(pattern2)) {
|
||
typeCheck(a) && ImgArr.push(getThat(2, a));
|
||
}
|
||
}
|
||
});
|
||
}
|
||
});
|
||
|
||
document.querySelectorAll("style").forEach(css => {
|
||
const str = css.innerText;
|
||
if (str.match(pattern1)) {
|
||
for (let a of str.match(pattern1)) {
|
||
typeCheck(a) && ImgArr.push(getThat(1, a));
|
||
}
|
||
}
|
||
if (str.match(pattern2)) {
|
||
for (let a of str.match(pattern2)) {
|
||
typeCheck(a) && ImgArr.push(getThat(2, a));
|
||
}
|
||
}
|
||
});
|
||
|
||
const bodyStr = document.body.innerHTML;
|
||
if (bodyStr.match(pattern1)) {
|
||
for (let a of bodyStr.match(pattern1)) {
|
||
typeCheck(a) && ImgArr.push(getThat(1, a));
|
||
}
|
||
}
|
||
if (bodyStr.match(pattern2)) {
|
||
for (let a of bodyStr.match(pattern2)) {
|
||
typeCheck(a) && ImgArr.push(getThat(2, a));
|
||
}
|
||
}
|
||
|
||
for (let e of document.querySelectorAll("img")) {
|
||
e.src && ImgArr.push(e.src);
|
||
}
|
||
callout();
|
||
};
|
||
|
||
// 加载全部并回调
|
||
const finalStep = () => {
|
||
total = ImgArr.length;
|
||
|
||
const loader = src => {
|
||
return new Promise((success, fail) => {
|
||
const img = new Image();
|
||
img.src = src;
|
||
img.onerror = fail;
|
||
|
||
if (img.complete) {
|
||
cur++;
|
||
success();
|
||
} else {
|
||
img.onload = () => {
|
||
cur++;
|
||
success();
|
||
};
|
||
}
|
||
});
|
||
};
|
||
|
||
//加载中
|
||
let loadStepFrame;
|
||
|
||
Promise.all(ImgArr.map(e => loader(e))).catch(err => {
|
||
cancelAnimationFrame(loadStepFrame);
|
||
error(err);
|
||
console.error(`[${Alphabet[8]} - ImgLoader]`, err);
|
||
});
|
||
|
||
const loadStep = () => {
|
||
step = Math.floor((cur / total) * 100);
|
||
if (floatNum < 100) {
|
||
if (floatNum < step) lazy ? floatNum++ : (floatNum = step);
|
||
loading && loading(floatNum);
|
||
if (floatNum === 100) {
|
||
cancelAnimationFrame(loadStepFrame);
|
||
if (lazy) {
|
||
callback && callback();
|
||
} else {
|
||
setTimeout(callback);
|
||
}
|
||
} else {
|
||
loadStepFrame = requestAnimationFrame(loadStep);
|
||
}
|
||
}
|
||
};
|
||
loadStep();
|
||
};
|
||
|
||
this.get ? onlyContainer(this.get, finalStep) : allResources(finalStep);
|
||
|
||
return this;
|
||
}
|
||
//图片上传
|
||
ImgUpload(options) {
|
||
let config = {
|
||
//接口地址(类型:字符串)
|
||
apiUrl: null,
|
||
//格式限制(类型:字符串)
|
||
Format: "*",
|
||
//选择类型(可选参数:default、camera)
|
||
type: "default",
|
||
//限制数量(类型:数字)
|
||
Max: 1,
|
||
//压缩比例(类型:数字)
|
||
Quality: 100,
|
||
//尺寸裁切
|
||
Clip: {
|
||
//宽度(类型:数字)
|
||
width: null,
|
||
//高度(类型:数字)
|
||
height: null,
|
||
},
|
||
//是否总是覆盖
|
||
alwaysCover: !1,
|
||
//上传事件
|
||
Events: {
|
||
//超过限制(类型:方法)
|
||
overMax: null,
|
||
//开始上传(类型:方法)
|
||
ready: null,
|
||
//上传中(类型:方法;返回类型:数字)
|
||
progress: null,
|
||
//上传成功(类型:方法;返回类型:对象)
|
||
success: null,
|
||
//失败(类型:方法)
|
||
fail() {
|
||
console.error(`[${Alphabet[8]} - ImgUpload] 上传失败!`);
|
||
},
|
||
},
|
||
//唯一id(类型:字符串;如果为null,则启用临时上传,请谨慎使用)
|
||
Uid: null,
|
||
};
|
||
config = this.extend(config, options);
|
||
const innerHtml = this.html(),
|
||
{ apiUrl, Format, type, Max, Quality, Clip, alwaysCover, Events, Uid } = config;
|
||
this.empty();
|
||
this.get.insertAdjacentHTML("afterbegin", `<label for="Pd_imgUpload_${this.pid}" style="width:100%;height:100%;display:block"></label>`);
|
||
|
||
const uploadBtn = document.createElement(`input`);
|
||
let userId,
|
||
total = 0,
|
||
currentIndex = 0,
|
||
stepsTotal = 0,
|
||
stepsOnly = 0,
|
||
finalTotal = 0;
|
||
|
||
if (Uid) {
|
||
userId = Uid;
|
||
} else {
|
||
userId = `${document.domain}_${this.pid}`;
|
||
}
|
||
|
||
uploadBtn.type = "file";
|
||
uploadBtn.accept = `image/${Format}`;
|
||
uploadBtn.id = `Pd_imgUpload_${this.pid}`;
|
||
uploadBtn.setAttribute("capture", type);
|
||
uploadBtn.hidden = !0;
|
||
|
||
if (Max > 1) uploadBtn.multiple = !0;
|
||
const label = this.get.querySelector(`label`);
|
||
label.innerHTML = innerHtml;
|
||
label.append(uploadBtn);
|
||
|
||
//上传图片
|
||
const uploadPreview = obj => {
|
||
const formData = new FormData();
|
||
let waitUploadFile = obj;
|
||
if (alwaysCover) waitUploadFile = new File([obj], `cover.${obj.name.split(".")[1]}`, { type: obj.type });
|
||
formData.append("images", waitUploadFile);
|
||
formData.append("uid", userId);
|
||
formData.append("width", Clip.width);
|
||
formData.append("height", Clip.height);
|
||
formData.append("quality", Quality);
|
||
|
||
Events.ready && Events.ready();
|
||
|
||
this.ajax({
|
||
url: `${apiUrl}`,
|
||
type: "post",
|
||
dataType: "form",
|
||
async: !0,
|
||
headers: null,
|
||
data: formData,
|
||
progress(progress) {
|
||
if (total > 1) {
|
||
if (progress == 100) currentIndex++;
|
||
stepsTotal = Math.floor((currentIndex / total) * 100);
|
||
Events.progress(stepsTotal);
|
||
} else {
|
||
stepsOnly = progress;
|
||
Events.progress(stepsOnly);
|
||
}
|
||
},
|
||
})
|
||
.then(res => {
|
||
if (res) {
|
||
if (total > 1) {
|
||
finalTotal = stepsTotal;
|
||
} else {
|
||
finalTotal = stepsOnly;
|
||
}
|
||
uploadBtn.setAttribute("data-progress", finalTotal);
|
||
if (finalTotal === 100) {
|
||
const data = { src: res.images };
|
||
Events.success && Events.success(data);
|
||
}
|
||
} else {
|
||
alert("发生错误!");
|
||
console.error(`[${Alphabet[8]} - ImgUpload] 服务端错误!`);
|
||
}
|
||
})
|
||
.catch(Events.fail);
|
||
};
|
||
|
||
//获取选择文件
|
||
const selectedFile = Files => {
|
||
const files = Array.prototype.slice.call(Files);
|
||
(total = 0), (currentIndex = 0), (stepsTotal = 0), (stepsOnly = 0), (finalTotal = 0);
|
||
|
||
if (Max === 0 || files.length <= Max) {
|
||
total = files.length;
|
||
|
||
if (total > 0) {
|
||
files.forEach((file, idx) => {
|
||
uploadPreview(Files[idx]);
|
||
});
|
||
}
|
||
} else {
|
||
Events.overMax && Events.overMax();
|
||
console.info(`[${Alphabet[7]} - ImgUpload] 超过最大数量:${Max}!`);
|
||
}
|
||
};
|
||
|
||
//选择文件按钮事件
|
||
uploadBtn.addEventListener("change", event => {
|
||
event.preventDefault();
|
||
selectedFile(event.target.files);
|
||
});
|
||
//拖动文件事件
|
||
this.bind("dragover", event => {
|
||
event.preventDefault();
|
||
});
|
||
this.bind("drop", event => {
|
||
event.preventDefault();
|
||
selectedFile(event.dataTransfer.files);
|
||
});
|
||
|
||
return this;
|
||
}
|
||
//图片移动缩放
|
||
ImgTransit(options) {
|
||
let config = {
|
||
//显示控制图标(类型:布尔)
|
||
icon: !0,
|
||
//控制图标大小(类型:数字)
|
||
iconSize: 30,
|
||
//显示边框(类型:布尔)
|
||
border: !0,
|
||
//开启多点触控(类型:布尔)
|
||
Gesture: !1,
|
||
//内边距(类型:数字)
|
||
padding: 10,
|
||
//缩放
|
||
scale: {
|
||
//是否启用(类型:布尔)
|
||
enable: !0,
|
||
//最小(类型:数字)
|
||
min: 80,
|
||
//最大(类型:数字)
|
||
max: 150,
|
||
//速率(类型:数字)
|
||
rate: 1,
|
||
},
|
||
//旋转
|
||
rotate: {
|
||
//是否启用(类型:布尔)
|
||
enable: !0,
|
||
//速率(类型:数字)
|
||
rate: 1,
|
||
},
|
||
//是否启用删除(类型:布尔)
|
||
delete: !0,
|
||
//边界限制(类型:布尔)
|
||
bounds: !0,
|
||
//边界可超出范围(类型:数字)
|
||
outBounds: 0,
|
||
//操作回调方法(类型:方法;返回类型:对象)
|
||
callback: null,
|
||
};
|
||
config = this.extend(config, options);
|
||
const that = this.get,
|
||
btnAnimation = "transition:opacity .2s ease-in",
|
||
imgs = that.querySelectorAll("img");
|
||
|
||
this.hide();
|
||
// 创建容器
|
||
if (!document.querySelector(".PD-TransitBox")) {
|
||
that.insertAdjacentHTML("afterend", "<div class='PD-TransitBox'></div>");
|
||
document.querySelector(".PD-TransitBox").style.cssText = `position:relative;touch-action:none;`;
|
||
}
|
||
const TransitBox = document.querySelector(".PD-TransitBox");
|
||
for (let the of imgs) {
|
||
TransitBox.appendChild(the);
|
||
the.parentNode.removeChild(the);
|
||
}
|
||
|
||
//图标配置
|
||
const iconStyle = option => {
|
||
let positionConfig = { top: null, left: null, right: null, bottom: null, name: null };
|
||
positionConfig = this.extend(positionConfig, option);
|
||
return `<a class="Pd-ImgTransit-btn Pd-${positionConfig.name}" style="width:${config.iconSize}px;height:${config.iconSize}px;background:#fff url('${
|
||
icoConfig[positionConfig.name]
|
||
}');background-position:center;background-repeat:no-repeat;background-size:65%;position:absolute;border-radius:50%;top:${positionConfig.top}px;left:${positionConfig.left}px;right:${
|
||
positionConfig.right
|
||
}px;bottom:${positionConfig.bottom}px;z-index:2;${btnAnimation}" href="javascript:void 0"></a>`;
|
||
};
|
||
|
||
const icon = {
|
||
resize: iconStyle({ left: `-${config.iconSize / 2}`, bottom: `-${config.iconSize / 2}`, name: "resize" }),
|
||
rotate: iconStyle({ right: `-${config.iconSize / 2}`, top: `-${config.iconSize / 2}`, name: "rotate" }),
|
||
delete: iconStyle({ left: `-${config.iconSize / 2}`, top: `-${config.iconSize / 2}`, name: "delete" }),
|
||
};
|
||
|
||
//设置参数
|
||
const setConfig = (ele, eleConfig) => {
|
||
for (let a of ele.querySelectorAll(`.Pd-ImgTransit-btn`)) a.style.transform = `scale(${1 / (eleConfig.scale / 100)}) rotate(${-1 * eleConfig.rotate}deg)`;
|
||
return (ele.style.transform = `translate3d(${eleConfig.translate}) scale(${eleConfig.scale / 100}) rotate(${eleConfig.rotate}deg)`);
|
||
};
|
||
|
||
//获取中心
|
||
const getCenterPoint = ele => {
|
||
return {
|
||
x: ele.getBoundingClientRect().left + ele.offsetWidth / 2,
|
||
y: ele.getBoundingClientRect().top + ele.offsetHeight / 2,
|
||
};
|
||
};
|
||
|
||
// 获取两点距离
|
||
const getDistance = (p1, p2) => {
|
||
const x = p2.pageX - p1.pageX,
|
||
y = p2.pageY - p1.pageY;
|
||
return Math.sqrt(x * x + y * y);
|
||
};
|
||
|
||
// 获取两点角度
|
||
const getAngle = (p1, p2) => {
|
||
const x = p1.pageX - p2.pageX,
|
||
y = p1.pageY - p2.pageY;
|
||
return (Math.atan2(y, x) * 180) / Math.PI;
|
||
};
|
||
|
||
// 多点触控
|
||
const setGesture = el => {
|
||
let obj = {}; //定义一个对象
|
||
let isTouch = !1;
|
||
let start = [];
|
||
el.addEventListener(
|
||
"touchstart",
|
||
e => {
|
||
if (e.touches.length >= 2) {
|
||
//判断是否有两个点在屏幕上
|
||
isTouch = !0;
|
||
start = e.touches; //得到第一组两个点
|
||
obj.gesturestart && obj.gesturestart.call(el); //执行gesturestart方法
|
||
}
|
||
},
|
||
!1
|
||
);
|
||
document.addEventListener(
|
||
"touchmove",
|
||
e => {
|
||
e.preventDefault();
|
||
if (e.touches.length >= 2 && isTouch) {
|
||
const now = e.touches, //得到第二组两个点
|
||
scale = getDistance(now[0], now[1]) / getDistance(start[0], start[1]), //得到缩放比例,getDistance是勾股定理的一个方法
|
||
rotation = getAngle(now[0], now[1]) - getAngle(start[0], start[1]); //得到旋转角度,getAngle是得到夹角的一个方法
|
||
|
||
e.scale = scale.toFixed(2);
|
||
e.rotation = rotation.toFixed(2);
|
||
obj.gesturemove && obj.gesturemove.call(el, e); //执行gesturemove方法
|
||
}
|
||
},
|
||
!1
|
||
);
|
||
document.addEventListener(
|
||
"touchend",
|
||
() => {
|
||
if (isTouch) {
|
||
isTouch = !1;
|
||
obj.gestureend && obj.gestureend.call(el); //执行gestureend方法
|
||
}
|
||
},
|
||
!1
|
||
);
|
||
return obj;
|
||
};
|
||
// 添加事件
|
||
const addEvent = ele => {
|
||
//添加容器事件
|
||
let touchStart,
|
||
touchEnd,
|
||
touchMove,
|
||
touchResize,
|
||
touchRotate,
|
||
touchDelete,
|
||
centerPoint,
|
||
prevAngle,
|
||
touchX = 0,
|
||
touchY = 0,
|
||
startX = 0,
|
||
startY = 0,
|
||
prevScale = 100;
|
||
|
||
const eleReal = ele,
|
||
eleConfig = { translate: `0,0,0`, scale: 100, rotate: 0 },
|
||
w = eleReal.offsetWidth,
|
||
h = eleReal.offsetHeight;
|
||
|
||
eleReal.style.width = `${w}px`;
|
||
eleReal.style.height = `${h}px`;
|
||
setConfig(eleReal, eleConfig);
|
||
eleReal.style.position = "absolute";
|
||
eleReal.style.top = eleReal.style.left = "50%";
|
||
eleReal.style.margin = `-${h / 2 + config.padding}px 0 0 -${w / 2 + config.padding}px`;
|
||
eleReal.style.padding = `${config.padding}px`;
|
||
|
||
//选中元素
|
||
touchStart = event => {
|
||
event.preventDefault();
|
||
if (event.target.className.indexOf("pd_child") < 0) {
|
||
startX = event.changedTouches[0].pageX - touchX;
|
||
startY = event.changedTouches[0].pageY - touchY;
|
||
event.target.style.transform = "scale(1.04)";
|
||
config.callback && config.callback({ type: "choose", obj: event.target.parentElement });
|
||
}
|
||
};
|
||
touchEnd = event => {
|
||
if (event.target.className.indexOf("pd_child") < 0) event.target.style.transform = "scale(1)";
|
||
};
|
||
//移动事件
|
||
touchMove = event => {
|
||
if (event.touches.length < 2 && event.target.className.indexOf("pd_child") < 0) {
|
||
const nowX = event.changedTouches[0].pageX,
|
||
nowY = event.changedTouches[0].pageY,
|
||
w = event.target.getBoundingClientRect().width,
|
||
h = event.target.getBoundingClientRect().height,
|
||
icon = event.target.parentElement.querySelectorAll(`.Pd-ImgTransit-btn`)[0].getBoundingClientRect(),
|
||
iconW = icon.width / 2,
|
||
getBounding = event.target.parentElement.parentElement.getBoundingClientRect(),
|
||
parentBox = {
|
||
width: config.bounds ? getBounding.width + config.outBounds : getBounding.width,
|
||
height: config.bounds ? getBounding.height + config.outBounds : getBounding.height,
|
||
};
|
||
|
||
touchX = nowX - startX;
|
||
touchY = nowY - startY;
|
||
if (config.bounds) {
|
||
if (Math.abs(touchX) >= parentBox.width / 2 - w / 2 - iconW) {
|
||
if (touchX < 0) {
|
||
touchX = -1 * (parentBox.width / 2 - w / 2 - iconW);
|
||
} else {
|
||
touchX = parentBox.width / 2 - w / 2 - iconW;
|
||
}
|
||
}
|
||
if (Math.abs(touchY) >= parentBox.height / 2 - h / 2 - iconW) {
|
||
if (touchY < 0) {
|
||
touchY = -1 * (parentBox.height / 2 - h / 2 - iconW);
|
||
} else {
|
||
touchY = parentBox.height / 2 - h / 2 - iconW;
|
||
}
|
||
}
|
||
}
|
||
eleConfig.translate = `${touchX}px,${touchY}px,0`;
|
||
setConfig(eleReal, eleConfig);
|
||
config.callback && config.callback({ type: "move", obj: eleReal });
|
||
}
|
||
};
|
||
//缩放事件
|
||
touchResize = event => {
|
||
event.stopImmediatePropagation();
|
||
event.preventDefault();
|
||
const x = event.changedTouches[0].pageX - eleReal.getBoundingClientRect().left;
|
||
if (x > 0 && eleConfig.scale > config.scale.min) eleConfig.scale -= config.scale.rate;
|
||
if (x < 0 && eleConfig.scale < config.scale.max) eleConfig.scale += config.scale.rate;
|
||
if (event.touches.length >= 2) {
|
||
if (config.scale.enable) {
|
||
prevScale = event.scale * 100;
|
||
eleConfig.scale = prevScale;
|
||
}
|
||
if (config.rotate.enable) eleConfig.rotate = event.rotation;
|
||
}
|
||
setConfig(eleReal, eleConfig);
|
||
config.callback && config.callback({ type: "resize", obj: eleReal });
|
||
};
|
||
//旋转事件
|
||
touchRotate = event => {
|
||
event.stopImmediatePropagation();
|
||
event.preventDefault();
|
||
const angle = Math.atan2(event.changedTouches[0].pageY - centerPoint.y, event.changedTouches[0].pageX - centerPoint.x);
|
||
eleConfig.rotate = Math.floor(((angle - prevAngle) * 180) / Math.PI) * config.rotate.rate;
|
||
setConfig(eleReal, eleConfig);
|
||
config.callback && config.callback({ type: "rotate", obj: eleReal });
|
||
};
|
||
//删除事件
|
||
touchDelete = event => {
|
||
event.stopImmediatePropagation();
|
||
event.preventDefault();
|
||
eleConfig.translate = "0,0,0";
|
||
eleConfig.rotate = 0;
|
||
eleConfig.scale = 100;
|
||
setConfig(eleReal, eleConfig);
|
||
eleReal.style.display = "none";
|
||
config.callback && config.callback({ type: "delete", obj: eleReal });
|
||
};
|
||
//绑定所有操作
|
||
eleReal.addEventListener("touchstart", touchStart);
|
||
eleReal.addEventListener("touchend", touchEnd);
|
||
eleReal.addEventListener("touchmove", touchMove);
|
||
if (config.scale.enable && config.rotate.enable && config.Gesture) {
|
||
setGesture(eleReal).gesturemove = e => {
|
||
touchResize(e);
|
||
touchRotate(e);
|
||
};
|
||
}
|
||
if (config.icon && config.scale.enable) eleReal.querySelectorAll(`.Pd-resize`)[0].addEventListener("touchmove", touchResize);
|
||
if (config.icon && config.rotate.enable) {
|
||
eleReal.querySelectorAll(`.Pd-rotate`)[0].addEventListener("touchstart", event => {
|
||
centerPoint = getCenterPoint(eleReal);
|
||
prevAngle = Math.atan2(event.changedTouches[0].pageY - centerPoint.y, event.changedTouches[0].pageX - centerPoint.x) - (eleConfig.rotate * Math.PI) / 180;
|
||
});
|
||
eleReal.querySelectorAll(`.Pd-rotate`)[0].addEventListener("touchmove", touchRotate);
|
||
}
|
||
if (config.icon && config.delete) eleReal.querySelectorAll(`.Pd-delete`)[0].addEventListener("touchstart", touchDelete);
|
||
};
|
||
|
||
//隐藏操作按钮
|
||
const hideBtn = () => {
|
||
const allCon = TransitBox.querySelectorAll(`.Pd-ImgTransit`),
|
||
allBtn = TransitBox.querySelectorAll(`.Pd-ImgTransit-btn`);
|
||
for (let a of allCon) {
|
||
a.style.border = "none";
|
||
a.style.zIndex = 1;
|
||
}
|
||
for (let a of allBtn) a.style.opacity = 0;
|
||
};
|
||
|
||
//显示操作按钮
|
||
const showBtn = tag => {
|
||
const curBtn = tag.querySelectorAll(`.Pd-ImgTransit-btn`);
|
||
for (let a of curBtn) {
|
||
a.style.opacity = 1;
|
||
if (config.border) tag.style.border = "2px dashed white";
|
||
tag.style.zIndex = 2;
|
||
}
|
||
};
|
||
|
||
// 初始化
|
||
for (let the of imgs) {
|
||
let btn = "";
|
||
if (config.icon) {
|
||
config.scale.enable && (btn += icon.resize);
|
||
config.rotate.enable && (btn += icon.rotate);
|
||
config.delete && (btn += icon.delete);
|
||
}
|
||
|
||
const TransitElement = document.createElement("div");
|
||
TransitElement.className = `Pd-ImgTransit pd_child_${the.alt}`;
|
||
TransitElement.style.position = "absolute";
|
||
the.style.transition = "transform .4s ease-in";
|
||
TransitElement.innerHTML = btn;
|
||
TransitElement.appendChild(the);
|
||
TransitBox.appendChild(TransitElement);
|
||
addEvent(TransitElement);
|
||
}
|
||
|
||
hideBtn();
|
||
//显示当前按钮
|
||
TransitBox.addEventListener("touchstart", event => {
|
||
hideBtn();
|
||
if (event.target !== TransitBox && event.target.className.indexOf("pd_child") < 0) {
|
||
config.icon ? showBtn(event.target.parentElement) : hideBtn();
|
||
event.target.zIndex = 1;
|
||
}
|
||
});
|
||
|
||
return this;
|
||
}
|
||
//微信SDK
|
||
wxSDK(options) {
|
||
let config = {
|
||
//相关接口地址(类型:字符串)
|
||
apiUrl: null,
|
||
//分享sdk版本
|
||
sdk: "https://res.wx.qq.com/open/js/jweixin-1.6.0.js",
|
||
//分享标题(类型:字符串或数组)
|
||
title: ["分享至朋友圈", "分享至好友"],
|
||
//分享描述(类型:字符串)
|
||
desc: "万事皆虚,万物皆允",
|
||
//分享图(类型:字符串或数组)
|
||
shareIcon: `https://${Alphabet[3]}/share_ico.jpg`,
|
||
//分享链接(类型:字符串或数组)
|
||
shareLinks: w.location.href,
|
||
//调试(类型:布尔)
|
||
debug: !1,
|
||
//微信jsApiList(类型:数组)
|
||
jsApiList: null,
|
||
//开放标签列表(类型:数组)
|
||
openTagList: null,
|
||
//回调方法
|
||
callback: {
|
||
//分享就绪(类型:方法)
|
||
ready: null,
|
||
//分享成功(类型:方法)
|
||
success: null,
|
||
//分享失败或取消(类型:方法)
|
||
error: null,
|
||
},
|
||
};
|
||
config = this.extend(config, options);
|
||
const scriptTag = document.createElement("script");
|
||
let { apiUrl, sdk, title, desc, shareLinks, debug, jsApiList, openTagList, callback, shareIcon } = config;
|
||
scriptTag.id = "Pd_share";
|
||
scriptTag.src = `${sdk}?${new Date().getTime()}`;
|
||
document.querySelector(`#Pd_share`) && document.querySelector(`#Pd_share`).remove();
|
||
document.body.appendChild(scriptTag);
|
||
let hasIcon = !1;
|
||
|
||
const isObj = con => {
|
||
if (typeof con === "object") {
|
||
return !0;
|
||
} else {
|
||
return !1;
|
||
}
|
||
};
|
||
|
||
document.querySelectorAll(`link`).forEach(tag => {
|
||
if (tag.getAttribute(`rel`) == "shortcut icon") {
|
||
hasIcon = !0;
|
||
shareIcon = tag.href;
|
||
}
|
||
});
|
||
|
||
if (hasIcon) {
|
||
const link = document.createElement(`link`);
|
||
link.rel = "shortcut icon";
|
||
link.href = isObj(shareIcon) ? shareIcon[0] : shareIcon;
|
||
link.type = "image/x-icon";
|
||
document.querySelector(`head`).appendChild(link);
|
||
}
|
||
|
||
let jsApiLists = ["onMenuShareTimeline", "onMenuShareAppMessage", "updateTimelineShareData", "updateAppMessageShareData"];
|
||
let openTagLists = ["wx-open-launch-app"];
|
||
if (jsApiList) {
|
||
jsApiList.map(e => {
|
||
jsApiLists.push(e);
|
||
});
|
||
}
|
||
if (openTagList) {
|
||
openTagList.map(e => {
|
||
openTagLists.push(e);
|
||
});
|
||
}
|
||
|
||
const timeLine = {
|
||
title: isObj(title) ? title[0] : title,
|
||
link: isObj(shareLinks) ? shareLinks[0] : shareLinks,
|
||
imgUrl: isObj(shareIcon) ? shareIcon[0] : shareIcon,
|
||
},
|
||
friend = {
|
||
title: isObj(title) ? title[1] : title,
|
||
link: isObj(shareLinks) ? shareLinks[1] : shareLinks,
|
||
imgUrl: isObj(shareIcon) ? shareIcon[1] : shareIcon,
|
||
desc,
|
||
};
|
||
|
||
const success = res => {
|
||
const { appId, timestamp, nonceStr, signature } = res;
|
||
wx.config({ debug, appId, timestamp, nonceStr, signature, jsApiList: jsApiLists, openTagList: openTagLists });
|
||
wx.ready(() => {
|
||
new Promise(next => {
|
||
if (wx.onMenuShareTimeline) {
|
||
const { title, link, imgUrl } = timeLine;
|
||
const { success, error } = callback;
|
||
wx.onMenuShareTimeline({ title, link, imgUrl, success, error });
|
||
} else {
|
||
const { title, link, imgUrl } = timeLine;
|
||
const { success, error } = callback;
|
||
wx.updateTimelineShareData({ title, link, imgUrl, success, error });
|
||
}
|
||
if (wx.onMenuShareAppMessage) {
|
||
const { title, link, imgUrl, desc } = friend;
|
||
const { success, error } = callback;
|
||
wx.onMenuShareAppMessage({ title, desc, link, imgUrl, success, error });
|
||
} else {
|
||
const { title, link, imgUrl, desc } = friend;
|
||
const { success, error } = callback;
|
||
wx.updateAppMessageShareData({ title, desc, link, imgUrl, success, error });
|
||
}
|
||
next();
|
||
})
|
||
.then(callback.ready)
|
||
.catch(err => {
|
||
console.error(`[${Alphabet[8]} - wxSDK]`, err);
|
||
});
|
||
});
|
||
};
|
||
|
||
scriptTag.onload = () => {
|
||
this.ajax({ url: `${apiUrl}${encodeURIComponent(w.location.href.split(`#`)[0])}` }).then(success);
|
||
};
|
||
|
||
return this;
|
||
}
|
||
//懒加载
|
||
LazyLoad(options) {
|
||
let config = {
|
||
//缺省尺寸
|
||
width: 100,
|
||
height: 100,
|
||
//缺省图标(类型:字符串)
|
||
icon: icoConfig.load,
|
||
};
|
||
config = this.extend(config, options);
|
||
const imgArr = this.child(`img`).get,
|
||
{ width, height, icon } = config;
|
||
let cur = 0,
|
||
lazyArr = [];
|
||
|
||
//遍历所有图片
|
||
for (let img of imgArr) {
|
||
if (img.dataset.src) {
|
||
img.width = width;
|
||
img.height = height;
|
||
img.style.background = `url("${icon}") no-repeat center,black`;
|
||
img.style.backgroundSize = `20%`;
|
||
lazyArr.push(img);
|
||
}
|
||
}
|
||
|
||
//进入视图
|
||
const inView = obj => {
|
||
if (obj.getBoundingClientRect().y - w.innerHeight < 0) return obj;
|
||
return !1;
|
||
};
|
||
|
||
//检测图片状态
|
||
const checker = () => {
|
||
lazyArr.forEach(img => {
|
||
if (inView(img) && !img.src && img.complete) {
|
||
img.src = inView(img).dataset.src;
|
||
img.style.transition = "all .8s ease";
|
||
|
||
img.onload = () => {
|
||
let newWidth = Number(img.dataset.width) || img.naturalWidth,
|
||
newHeight = Number(img.dataset.height) || img.naturalHeight;
|
||
|
||
if (img.dataset.width) newHeight = (newWidth / img.naturalWidth) * img.naturalHeight;
|
||
if (img.dataset.height) newWidth = (newHeight / img.naturalHeight) * img.naturalWidth;
|
||
|
||
img.width = newWidth;
|
||
img.height = newHeight;
|
||
img.removeAttribute("data-src");
|
||
img.style.background = null;
|
||
img.dataset.width && img.removeAttribute("data-width");
|
||
img.dataset.height && img.removeAttribute("data-height");
|
||
cur++;
|
||
if (cur == lazyArr.length) w.removeEventListener("scroll", checker);
|
||
|
||
img.addEventListener("transitionend", () => {
|
||
img.style.transition = null;
|
||
});
|
||
};
|
||
|
||
img.onerror = () => {
|
||
console.error(`[${Alphabet[8]} - LazyLoad] 发生错误:${img.src}!`);
|
||
cur++;
|
||
};
|
||
}
|
||
});
|
||
};
|
||
|
||
//页面滚动事件
|
||
w.addEventListener("scroll", checker);
|
||
checker();
|
||
|
||
return this;
|
||
}
|
||
//上传OSS
|
||
ossUpload(options) {
|
||
let config = {
|
||
// 阿里云账号AccessId(类型:字符串)
|
||
AccessId: null,
|
||
// 阿里云账号AccessKey(类型:字符串)
|
||
AccessKey: null,
|
||
// OSS Bucket 外网域名(类型:字符串)
|
||
Endpoint: null,
|
||
// 文件大小限制(类型:整数;单位:MB)
|
||
maxSize: 2,
|
||
};
|
||
config = this.extend(config, options);
|
||
const that = this;
|
||
const { AccessId, AccessKey, Endpoint, maxSize } = config;
|
||
|
||
// 引用检测
|
||
try {
|
||
Crypto;
|
||
} catch (err) {
|
||
return console.error(`[${Alphabet[8]}] 缺少Crypto工具方法`, err);
|
||
}
|
||
if (!Crypto.HMAC) return console.error(`[${Alphabet[8]}] 缺少Crypto工具的HMAC方法`);
|
||
if (!Crypto.SHA1) return console.error(`[${Alphabet[8]}] 缺少Crypto工具的SHA1方法`);
|
||
|
||
// 配置检测
|
||
if (!AccessId) return console.error(`[${Alphabet[8]}] 缺失阿里云账号AccessId`);
|
||
if (!AccessKey) return console.error(`[${Alphabet[8]}] 缺失阿里云账号AccessKey`);
|
||
if (!Endpoint) return console.error(`[${Alphabet[8]}] 缺失OSS Bucket 外网域名`);
|
||
|
||
// 自动补零
|
||
const padThat = str => {
|
||
return str.toString().padStart(2, 0);
|
||
};
|
||
|
||
// 客户端签名
|
||
const policyText = {
|
||
// 获取失效时间
|
||
expiration: (function () {
|
||
let date;
|
||
const Year = new Date().getFullYear(),
|
||
Month = new Date().getMonth() + 1,
|
||
Day = new Date().getDate(),
|
||
Hours = new Date().getHours();
|
||
|
||
date = `${Year}-${padThat(Month)}-${padThat(Day)}T${padThat(Hours)}:00:00.000Z`;
|
||
return date;
|
||
})(),
|
||
conditions: [
|
||
["content-length-range", 0, maxSize * 1024 * 1024], // 设置上传文件的大小限制
|
||
],
|
||
};
|
||
|
||
// 获取拓展名
|
||
const getSuffix = filename => {
|
||
return filename.substring(filename.lastIndexOf("."));
|
||
};
|
||
|
||
// 上传文件
|
||
const uploadFile = obj => {
|
||
let {
|
||
// 待上传文件(类型:二进制)
|
||
fileObj = null,
|
||
// 文件名(类型:字符串,默认生成随机文件名)
|
||
fileName = that.guid(),
|
||
// 上传目录名称(类型:字符串,默认根目录)
|
||
dirName = "",
|
||
// 上传请求头(类型:对象)
|
||
headers = null,
|
||
// 是否开启同步上传(类型:布尔值)
|
||
async = !0,
|
||
// 上传中回调(类型:方法;返回类型:数字)
|
||
progress = null,
|
||
} = obj;
|
||
|
||
const policyBase64 = OSSBase64.encode(JSON.stringify(policyText)),
|
||
bytes = Crypto.HMAC(Crypto.SHA1, policyBase64, AccessKey, { asBytes: !0 }),
|
||
signature = Crypto.util.bytesToBase64(bytes);
|
||
|
||
return new Promise((resolve, reject) => {
|
||
if (fileObj) {
|
||
if (fileObj.size > maxSize * 1024 * 1024) {
|
||
reject("overSize");
|
||
return console.warn(`[${Alphabet[9]}] 文件大小超出最大限制`);
|
||
} else {
|
||
const formData = new FormData();
|
||
formData.append("name", `${fileName}${getSuffix(fileObj.name)}`);
|
||
const copyFile = new File([fileObj], `${fileName}${getSuffix(fileObj.name)}`, { type: fileObj.type });
|
||
fileObj = copyFile;
|
||
formData.append("key", dirName ? `${dirName}/\${filename\}` : "${filename}");
|
||
formData.append("policy", policyBase64);
|
||
formData.append("OSSAccessKeyId", AccessId);
|
||
formData.append("success_action_status", "200");
|
||
formData.append("signature", signature);
|
||
formData.append("file", fileObj);
|
||
|
||
that
|
||
.ajax({
|
||
url: Endpoint,
|
||
type: "post",
|
||
headers,
|
||
async,
|
||
dataType: "form",
|
||
data: formData,
|
||
progress,
|
||
})
|
||
.then(() => {
|
||
resolve({
|
||
code: 200,
|
||
msg: "上传成功",
|
||
url: (function () {
|
||
let url;
|
||
if (dirName != "") {
|
||
url = `${Endpoint}/${dirName}/${fileObj.name}`;
|
||
} else {
|
||
url = `${Endpoint}/${fileObj.name}`;
|
||
}
|
||
return url;
|
||
})(),
|
||
});
|
||
})
|
||
.catch(reject);
|
||
}
|
||
} else {
|
||
reject("noFile");
|
||
return console.warn(`[${Alphabet[9]}] 请选择需要上传的文件`);
|
||
}
|
||
});
|
||
};
|
||
|
||
this.start = uploadFile;
|
||
return this;
|
||
}
|
||
};
|
||
};
|
||
|
||
const Pandora = class extends PandoraJs(PandoraEX) {
|
||
constructor(obj = null) {
|
||
super(obj);
|
||
}
|
||
};
|
||
|
||
w.Pandora = Pandora;
|
||
// 判断是否引用了JQuery或者Zepto
|
||
if (!w.$) {
|
||
w.$ = obj => {
|
||
return new Pandora(obj);
|
||
};
|
||
}
|
||
})(window || global || self || this);
|