# 一文了解 Layui
Layui 是一套开源免费的 Web UI 组件库,采用自身轻量级模块化规范,遵循原生态的 HTML/CSS/JavaScript 开发模式,极易上手,拿来即用。其风格简约轻盈,而内在雅致丰盈,甚至包括文档在内的每一处细节都经过精心雕琢,非常适合网页界面的快速构建。Layui 区别于一众主流的前端框架,却并非逆道而行,而是信奉返璞归真之道。确切地说,它更多是面向于追求简单的务实主义者,即无需涉足各类构建工具,只需面向浏览器本身,便可将页面所需呈现的元素与交互信手拈来。
# 基本结构
Layui 框架最基本的结构是一个立即执行函数
;!function(win){
"use strict";
// ...
})(window)
# 基本声明
!(function (win) {
"use strict";
const Layui = function(){
this.v = '2.7.5'; // layui 版本号
}
GLOBAL = win.LAYUI_GLOBAL || {} //识别预先可能定义的指定全局对象
//exports layui
win.layui = new Layui();
})(window);
# 基本配置
!(function (win) {
"use strict";
const Layui = function () {
this.v = "2.7.5"; // layui 版本号
};
GLOBAL = win.LAYUI_GLOBAL || {}; //识别预先可能定义的指定全局对象
const doc = win.document;
const config = {
modules: {}, // 模块物理路径
status: {}, // 模块加载状态
timeout: 10, // 符合规范的模块请求最长等待秒数
event: {} // 模块自定义事件
};
//记录基础数据
Layui.prototype.cache = config;
//exports layui
win.layui = new Layui();
})(window);
# 模块系统
# 定义模块
//定义模块
Layui.prototype.define = function (deps, factory) {
var that = this,
type = typeof deps === "function",
callback = function () {
var setApp = function (app, exports) {
layui[app] = exports;
config.status[app] = true;
};
typeof factory === "function" &&
factory(function (app, exports) {
setApp(app, exports);
config.callback[app] = function () {
factory(setApp);
};
});
return this;
};
type && ((factory = deps), (deps = []));
that.use(deps, callback, null, "define");
return that;
};
# 使用模块
//使用特定模块
Layui.prototype.use = function (apps, callback, exports, from) {
var that = this,
dir = (config.dir = config.dir ? config.dir : getPath),
head = doc.getElementsByTagName("head")[0];
apps = (function () {
if (typeof apps === "string") {
return [apps];
}
//当第一个参数为 function 时,则自动加载所有内置模块,且执行的回调即为该 function 参数;
else if (typeof apps === "function") {
callback = apps;
return ["all"];
}
return apps;
})();
//如果页面已经存在 jQuery 1.7+ 库且所定义的模块依赖 jQuery,则不加载内部 jquery 模块
if (win.jQuery && jQuery.fn.on) {
that.each(apps, function (index, item) {
if (item === "jquery") {
apps.splice(index, 1);
}
});
layui.jquery = layui.$ = jQuery;
}
var item = apps[0],
timeout = 0;
exports = exports || [];
//静态资源host
config.host = config.host || (dir.match(/\/\/([\s\S]+?)\//) || ["//" + location.host + "/"])[0];
//加载完毕
function onScriptLoad(e, url) {
var readyRegExp = navigator.platform === "PLaySTATION 3" ? /^complete$/ : /^(complete|loaded)$/;
if (e.type === "load" || readyRegExp.test((e.currentTarget || e.srcElement).readyState)) {
config.modules[item] = url;
head.removeChild(node);
(function poll() {
if (++timeout > (config.timeout * 1000) / 4) {
return error(item + " is not a valid module", "error");
}
config.status[item] ? onCallback() : setTimeout(poll, 4);
})();
}
}
//回调
function onCallback() {
exports.push(layui[item]);
apps.length > 1
? that.use(apps.slice(1), callback, exports, from)
: typeof callback === "function" &&
(function () {
//保证文档加载完毕再执行回调
if (layui.jquery && typeof layui.jquery === "function" && from !== "define") {
return layui.jquery(function () {
callback.apply(layui, exports);
});
}
callback.apply(layui, exports);
})();
}
//如果引入了聚合板,内置的模块则不必重复加载
if (apps.length === 0 || (layui["layui.all"] && modules[item])) {
return onCallback(), that;
}
//获取加载的模块 URL
//如果是内置模块,则按照 dir 参数拼接模块路径
//如果是扩展模块,则判断模块路径值是否为 {/} 开头,
//如果路径值是 {/} 开头,则模块路径即为后面紧跟的字符。
//否则,则按照 base 参数拼接模块路径
var url =
(modules[item] ? dir + "modules/" : /^\{\/\}/.test(that.modules[item]) ? "" : config.base || "") +
(that.modules[item] || item) +
".js";
url = url.replace(/^\{\/\}/, "");
//如果扩展模块(即:非内置模块)对象已经存在,则不必再加载
if (!config.modules[item] && layui[item]) {
config.modules[item] = url; //并记录起该扩展模块的 url
}
//首次加载模块
if (!config.modules[item]) {
var node = doc.createElement("script");
node.async = true;
node.charset = "utf-8";
node.src =
url +
(function () {
var version = config.version === true ? config.v || new Date().getTime() : config.version || "";
return version ? "?v=" + version : "";
})();
head.appendChild(node);
if (
node.attachEvent &&
!(node.attachEvent.toString && node.attachEvent.toString().indexOf("[native code") < 0) &&
!isOpera
) {
node.attachEvent("onreadystatechange", function (e) {
onScriptLoad(e, url);
});
} else {
node.addEventListener(
"load",
function (e) {
onScriptLoad(e, url);
},
false
);
}
config.modules[item] = url;
} else {
//缓存
(function poll() {
if (++timeout > (config.timeout * 1000) / 4) {
return error(item + " is not a valid module", "error");
}
typeof config.modules[item] === "string" && config.status[item] ? onCallback() : setTimeout(poll, 4);
})();
}
return that;
};
# 拓展模块
//拓展模块
Layui.prototype.extend = function(options){
var that = this;
//验证模块是否被占用
options = options || {};
for(var o in options){
if(that[o] || that.modules[o]){
error(o+ ' Module already exists', 'error');
} else {
that.modules[o] = options[o];
}
}
return that;
};
# 事件系统
# 插件系统
# 工具方法
# getStyle
//获取节点的 style 属性值
Layui.prototype.getStyle = function(node, name){
var style = node.currentStyle ? node.currentStyle : win.getComputedStyle(node, null);
return style[style.getPropertyValue ? 'getPropertyValue' : 'getAttribute'](name);
};
# img
//图片预加载
Layui.prototype.img = function(url, callback, error) {
var img = new Image();
img.src = url;
if(img.complete){
return callback(img);
}
img.onload = function(){
img.onload = null;
typeof callback === 'function' && callback(img);
};
img.onerror = function(e){
img.onerror = null;
typeof error === 'function' && error(e);
};
};
# each
//遍历
Layui.prototype.each = function(obj, fn){
var key
,that = this
,callFn = function(key, obj){ //回调
return fn.call(obj[key], key, obj[key])
};
if(typeof fn !== 'function') return that;
obj = obj || [];
//优先处理数组结构
if(that.isArray(obj)){
for(key = 0; key < obj.length; key++){
if(callFn(key, obj)) break;
}
} else {
for(key in obj){
if(callFn(key, obj)) break;
}
}
return that;
}