# LayUI
# 实现原理
# 基本结构
立即执行函数
;!function(win){
"use strict";
// ...
})(window)
1
2
3
4
2
3
4
# 基本声明
!(function (win) {
"use strict";
const Layui = function(){
this.v = '2.7.5'; // layui 版本号
}
GLOBAL = win.LAYUI_GLOBAL || {} //识别预先可能定义的指定全局对象
//exports layui
win.layui = new Layui();
})(window);
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
# 基本配置
!(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);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 实现原理-模块系统
# 定义模块
//定义模块
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;
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 使用模块
//使用特定模块
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;
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
# 拓展模块
//拓展模块
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;
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 一些方法
//获取节点的 style 属性值
Layui.prototype.getStyle = function(node, name){
var style = node.currentStyle ? node.currentStyle : win.getComputedStyle(node, null);
return style[style.getPropertyValue ? 'getPropertyValue' : 'getAttribute'](name);
};
1
2
3
4
5
2
3
4
5
//图片预加载
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);
};
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//遍历
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;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# 实现原理-事件系统