You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
text/web/layui.js

317 lines
15 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

// 立即执行函数,传入 window 对象(通常约定用 e 表示),开启严格模式,使代码遵循更严格的语法和语义规范,有助于发现潜在错误
;!function(e) {
"use strict";
// 获取文档对象,后续很多操作会基于此进行 DOM 相关操作
var t = document,
// 用于管理 layui 的各种内部状态和模块相关信息的对象
n = {
modules: {}, // 存放已加载或待加载的模块信息
status: {}, // 模块加载状态相关标记
timeout: 10, // 用于设置一些操作的超时时间相关阈值
event: {} // 事件管理相关对象,用于存储事件绑定等信息
},
// 构造函数,用于创建一个表示 layui 版本信息的对象实例,此处实例化后其 v 属性会被赋值为 "2.5.6"
r = function () {
this.v = "2.5.6"
},
// 获取当前脚本的源文件路径,通过判断 currentScript 以及遍历 scripts 集合等方式来确定路径
// 最终得到的是脚本所在目录路径(去除文件名部分)
o = function () {
var e = t.currentScript ? t.currentScript.src : function () {
for (var e, n = t.scripts, r = n.length - 1, o = r; o > 0; o--)
if ("interactive" === n[o].readyState) {
e = n[o].src;
break
}
return e || n[r].src
}();
return e.substring(0, e.lastIndexOf("/") + 1)
}(),
// 用于在控制台输出错误提示信息的函数,前提是 window.console 存在且有 console.error 方法可用
a = function (t) {
e.console && console.error && console.error("Layui hint: " + t)
},
// 判断是否是 Opera 浏览器(旧的判断方式,现在 Opera 已基于 Chromium 内核等情况可能不太常用了)
i = "undefined" != typeof opera && "[object Opera]" === opera.toString(),
// 定义了各个 layui 模块对应的路径映射关系,方便后续根据模块名去加载对应的模块文件
u = {
layer: "modules/layer",
laydate: "modules/laydate",
laypage: "modules/laypage",
laytpl: "modules/laytpl",
layim: "modules/layim",
layedit: "modules/layedit",
form: "modules/form",
upload: "modules/upload",
transfer: "modules/transfer",
tree: "modules/tree",
table: "modules/table",
element: "modules/element",
rate: "modules/rate",
colorpicker: "modules/colorpicker",
slider: "modules/slider",
carousel: "modules/carousel",
flow: "modules/flow",
util: "modules/util",
code: "modules/code",
jquery: "modules/jquery",
mobile: "modules/mobile",
"layui.all": "../layui.all"
};
// 将 n 对象(包含模块、状态等管理信息)挂载到 layui 实例的 cache 属性上,方便通过实例访问这些数据
r.prototype.cache = n;
// 用于定义模块的方法
r.prototype.define = function (e, t) {
var r = this,
// 判断传入的第一个参数是否是函数类型
o = "function" == typeof e,
// 内部函数,用于处理模块注册成功后的一些赋值和回调相关操作
a = function () {
var e = function (e, t) {
layui[e] = t,
n.status[e] = !0
};
return "function" == typeof t && t(function (r, o) {
e(r, o),
n.callback[r] = function () {
t(e)
}
}),
this
};
// 如果传入的第一个参数是函数,将第二个参数赋值给第一个参数,同时把第一个参数重置为空数组(处理参数顺序等情况)
return o && (t = e, e = []),
// 如果不存在 layui.all 且存在 layui.mobile调用内部函数 a 进行模块相关处理,否则调用 use 方法来处理模块定义
!layui["layui.all"] && layui["layui.mobile"] ? a.call(r) : (r.use(e, a), r)
};
// 模块加载的核心方法,用于加载指定的 layui 模块
r.prototype.use = function (e, r, l) {
function c(e, t) {
var r = "PLaySTATION 3" === navigator.platform ? /^complete$/ : /^(complete|loaded)$/;
// 判断脚本是否加载完成(根据不同浏览器平台判断方式略有不同),加载完成后执行后续逻辑
("load" === e.type || r.test((e.currentTarget || e.srcElement).readyState)) && (n.modules[d] = t, y.removeChild(h), function o() {
return ++m > 1e3 * n.timeout / 4 ? a(d + " is not a valid module") : void (n.status[d] ? s() : setTimeout(o, 4))
}())
}
function s() {
l.push(layui[d]),
e.length > 1 ? p.use(e.slice(1), r, l) : "function" == typeof r && r.apply(layui, l)
}
var p = this,
f = n.dir = n.dir ? n.dir : o,
y = t.getElementsByTagName("head")[0];
// 将传入的模块名参数统一处理为数组形式(如果是字符串则转换为单元素数组)
e = "string" == typeof e ? [e] : e;
// 如果 window.jQuery 存在且有 on 方法,移除要加载的模块列表中的 jquery 模块(避免重复加载,假设已经全局存在了 jQuery
window.jQuery && jQuery.fn.on && (p.each(e, function (t, n) {
"jquery" === n && e.splice(t, 1)
}), layui.jquery = layui.$ = jQuery);
var d = e[0],
m = 0;
// 如果传入的模块列表为空或者存在 layui.all 且对应的模块在 u 中有定义,或者不存在 layui.all 但存在 layui.mobile 且对应模块在 u 中有定义,直接执行后续逻辑(如执行回调等)
if (l = l || [], n.host = n.host || (f.match(/\/\/([\s\S]+?)\//) || ["//" + location.host + "/"])[0], 0 === e.length || layui["layui.all"] && u[d] || !layui["layui.all"] && layui["layui.mobile"] && u[d]) return s(), p;
var v = (u[d] ? f + "lay/" : /^\{\/\}/.test(p.modules[d]) ? "" : n.base || "") + (p.modules[d] || d) + ".js";
// 处理模块路径,如果模块路径已经存在于 modules 中则直接使用,否则根据一定规则拼接出完整的模块脚本路径
if (v = v.replace(/^\{\/\}/, ""), !n.modules[d] && layui[d] && (n.modules[d] = v), n.modules[d])
// 如果模块路径已经存在且模块状态已经是加载完成状态,直接执行后续逻辑,否则定时检查模块状态等待加载完成
!function g() {
return ++m > 1e3 * n.timeout / 4 ? a(d + " is not a valid module") : void ("string" == typeof n.modules[d] && n.status[d] ? s() : setTimeout(g, 4))
}();
else {
var h = t.createElement("script");
h.async = !0,
h.charset = "utf-8",
h.src = v + function () {
var e = n.version === !0 ? n.v || (new Date).getTime() : n.version || "";
return e ? "?v=" + e : ""
}(),
y.appendChild(h),
// 根据浏览器是否支持 attachEvent 以及其是否是原生代码等情况,选择合适的方式来监听脚本加载完成事件
!h.attachEvent || h.attachEvent.toString() && h.attachEvent.toString().indexOf("[native code") < 0 || i ? h.addEventListener("load", function (e) {
c(e, v)
}, !1) : h.attachEvent("onreadystatechange", function (e) {
c(e, v)
}),
n.modules[d] = v
}
return p
};
// 获取元素的样式属性值,兼容不同浏览器获取样式的方式(旧版 IE 用 currentStyle现代浏览器用 getComputedStyle
r.prototype.getStyle = function (t, n) {
var r = t.currentStyle ? t.currentStyle : e.getComputedStyle(t, null);
return r[r.getPropertyValue ? "getPropertyValue" : "getAttribute"](n)
};
// 用于加载 CSS 样式文件的方法,可传入样式文件路径、回调函数等,处理样式文件加载完成等相关逻辑并执行回调
r.prototype.link = function (e, r, o) {
var i = this,
u = t.createElement("link"),
l = t.getElementsByTagName("head")[0];
"string" == typeof r && (o = r);
var c = (o || e).replace(/\.|\//g, ""),
s = u.id = "layuicss-" + c,
p = 0;
return u.rel = "stylesheet",
u.href = e + (n.debug ? "?v=" + (new Date).getTime() : ""),
u.media = "all",
t.getElementById(s) || l.appendChild(u),
"function" != typeof r ? i : (function f() {
return ++p > 1e3 * n.timeout / 100 ? a(e + " timeout") : void (1989 === parseInt(i.getStyle(t.getElementById(s), "width")) ? function () {
r()
}() : setTimeout(f, 100))
}(), i)
};
// 根据模块名判断是否存在对应的模块以及相应的回调函数,并返回回调函数(如果存在)
r.prototype.factory = function (e) {
if (layui[e]) return "function" == typeof n.callback[e] ? n.callback[e] : null
};
// 辅助方法,用于添加指定的 CSS 文件,调用 link 方法并传入正确的路径来加载 CSS
r.prototype.addcss = function (e, t, r) {
return layui.link(n.dir + "css/" + e, t, r)
};
// 用于创建图片对象、处理图片加载完成、加载出错等不同情况并执行相应的回调函数
r.prototype.img = function (e, t, n) {
var r = new Image;
return r.src = e,
r.complete ? t(r) : (r.onload = function () {
r.onload = null,
"function" == typeof t && t(r)
},
void (r.onerror = function (e) {
r.onerror = null,
"function" == typeof n && n(e)
}))
};
// 用于配置 layui 的相关参数,将传入的配置对象属性赋值到内部管理的 n 对象对应的属性上
r.prototype.config = function (e) {
e = e || {};
for (var t in e) n[t] = e[t];
return this
};
// 返回定义的模块路径映射对象的副本,对外提供获取所有模块路径信息的方式
r.prototype.modules = function () {
var e = {};
for (var t in u) e[t] = u[t];
return e
}();
// 用于扩展 layui 的模块,添加新的模块路径映射,但会检查模块名是否已被占用,若已占用则输出错误提示
r.prototype.extend = function (e) {
var t = this;
e = e || {};
for (var n in e) t[n] || t.modules[n] ? a("模块名 " + n + " 已被占用") : t.modules[n] = e[n];
return t
};
// 用于解析 URL 的哈希部分,提取路径、查询参数和哈希值等信息,构建对应的对象返回
r.prototype.router = function (e) {
var t = this,
e = e || location.hash,
n = {
path: [],
search: {},
hash: (e.match(/[^#](#.*$)/) || [])[1] || ""
};
return /^#\//.test(e) ? (e = e.replace(/^#\//, ""), n.href = "/" + e, e = e.replace(/([^#])(#.*$)/, "$1").split("/") || [], t.each(e, function (e, t) {
/^\w+=/.test(t) ? function () {
t = t.split("="),
n.search[t[0]] = t[1]
}() : n.path.push(t)
}), n) : n
};
// 用于解析 URL提取路径名、查询参数、哈希值等信息构建包含这些信息的对象返回
r.prototype.url = function (e) {
var t = this,
n = {
pathname: function () {
var t = e ? function () {
var t = (e.match(/\.[^.]+?\/.+/) || [])[0] || "";
return t.replace(/^[^\/]+/, "").replace(/\?.+/, "")
}() : location.pathname;
return t.replace(/^\//, "").split("/")
}(),
search: function () {
var n = {},
r = (e ? function () {
var t = (e.match(/\?.+/) || [])[0] || "";
return t.replace(/\#.+/, "")
}() : location.search).replace(/^\?+/, "").split("&");
return t.each(r, function (e, t) {
var r = t.indexOf("="),
o = function () {
return r < 0 ? t.substr(0, t.length) : 0 !== r && t.substr(0, r)
}();
o && (n[o] = r > 0 ? t.substr(r + 1) : null)
}),
n
}(),
hash: t.router(function () {
return e ? (e.match(/#.+/) || [])[0] || "" : location.hash
}())
};
return n
};
// 用于在 localStorage 中存储或获取数据,支持以对象形式操作数据,可进行增删改查等操作,通过 JSON 序列化和反序列化来处理数据存储格式
r.prototype.data = function (t, n, r) {
if (t = t || "layui", r = r || localStorage, e.JSON && e.JSON.parse) {
if (null === n) return delete r[t];
n = "object" == typeof n ? n : {
key: n
};
try {
var o = JSON.parse(r[t])
} catch (a) {
var o = {}
}
return "value" in n && (o[n.key] = n.value),
n.remove && delete o[n.key],
r[t] = JSON.stringify(o),
n.key ? o[n.key] : o
}
};
// 类似于 data 方法,但操作的是 sessionStorage 而不是 localStorage用于临时存储会话相关数据
r.prototype.sessionData = function (e, t) {
return this.data(e, t, sessionStorage)
};
// 用于检测设备相关信息,如操作系统类型、是否是 IE 浏览器、是否是微信浏览器、是否是安卓或 iOS 等移动端设备等情况
r.prototype.device = function (t) {
var n = navigator.userAgent.toLowerCase(),
r = function (e) {
var t = new RegExp(e + "/([^\\s\\_\\-]+)");
return e = (n.match(t) || [])[1],
e || !1
},
o = {
os: function () {
return /windows/.test(n) ? "windows" : /linux/.test(n) ? "linux" : /iphone|ipod|ipad|ios/.test(n) ? "ios" : /mac/.test(n) ? "mac" : void 0
}(),
ie: function () {
return !!(e.ActiveXObject || "ActiveXObject" in e) && ((n.match(/msie\s(\d+)/) || [])[1] || "11")
}(),
weixin: r("micromessenger")
};
return t && !o[t] && (o[t] = r(t)),
o.android = /android/.test(n),
o.ios = "ios" === o.os,
o.mobile = !(!o)
}
}