文章目录
Layui源码分析
分析源码的目的
-
学习设计框架的理念
-
学习组件实现技巧
-
巩固JavaScript和jQuery知识
-
无限接近这些牛人!!!
什么是Layui
layui(谐音:类 UI) 是一套开源的 Web UI 解决方案,采用自身经典的模块化规范,并遵循原生 HTML/CSS/JS 的开发方式,极易上手,拿来即用。其风格简约轻盈,而组件优雅丰盈,从源代码到使用方法的每一处细节都经过精心雕琢,非常适合网页界面的快速开发。无需涉足前端各种工具,只需面对浏览器本身,让一切你所需要的元素与交互,从这里信手拈来。
从网站上看下载量,已经到达2160887次,即下载了216万多次,对于在程序开发的领域,有这么多次下载量总能说明问题。
设计layui的初衷
用大牛贤心说起来,当时要做layui目的很明确,就是:“由职业前端倾情打造,面向全层次的前后端开发者,易上手开箱即用的 Web UI 组件库”。贤心出发点很简单:满足服务端程序员的需求。在layui网站上,layui的特点:
- 返璞归真。
身处在前端社区的繁荣之下,我们都在有意或无意地追逐。而 layui 偏偏回望当初,奔赴在返璞归真的漫漫征途,自信并勇敢着,追寻于原生态的书写指令,试图以最简单的方式诠释高效
- 双面体验。
拥有双面的不仅是人生,还有 layui。一面极简,一面丰盈。极简是视觉所见的外在,是开发所念的简易。丰盈是倾情雕琢的内在,是信手拈来的承诺。一切本应如此,简而全,双重体验。
layui组件世界
layui的元素由以下组成:布局(栅格、后台布局)、颜色、字体图标、动画、按钮、表单、导航条、面包屑、选项卡、进度条、面板、静态表格、徽章、时间线、辅助元素等。
layui 提供了丰富的内置模块,他们皆可通过模块化的方式按需加载,其中包括:layer、layDate、layPage、laytpl、table、form、upload、element、tree、layeditor、rate、carousel、flow、util、code等。
Layui的模块化之路
Layui中怎么做模块,这是贤心按照js的传统创造的,是不与任何标准兼容的方案,所以很难把layui整合到其它项目中,但如果按layui为主标准,需要把其它的模块进行包装,改造成符合layui标准的模块,然后在layui中使用。模块思路采用了几年前的以浏览器为宿主的类 AMD 模块管理方式,却又并非受限于 CommonJS 的那些条条框框,它拥有自己的模式,更加轻量和简单。
layui 定义了一套更轻量的模块规范。并且这种方式在经过了大量的实践后,成为 layui 最核心的模块加载引擎。layui 通过 define方法定义模块,利用use 方法加载使用模块。所以先从define和use这两个方法说起。
LayUI的零依赖的部署方式和全模块的加载方式,就大概能知道LayUI的设计哲学了.
<link rel="stylesheet" href="/layui/css/layui.css">
<script src="/layui/layui.all.js"></script>
<script>
(function(){
var layer = layui.layer;
layer.msg('Hello World');
})();
</script>
JavaScript的模块化实现
通行的Javascript模块规范共有两种:CommonJS和AMD。
CommonJS
2009年,美国程序员Ryan Dahl创造了node.js项目,将javascript语言用于服务器端编程,这标志"Javascript模块化编程"正式诞生,在浏览器环境下,没有模块也不是特别大的问题,毕竟网页程序的复杂性有限;但是在服务器端,一定要有模块,与操作系统和其他应用程序互动,否则根本没法编程。node.js的模块系统,就是参照CommonJS规范实现的。在CommonJS中,有一个全局性方法require(),用于加载模块。假定有一个数学模块math.js,就可以像下面这样加载:
var math = require('math');
math.add(2,3); // 5
由于一个重大的局限,使得CommonJS规范不适用于浏览器环境:
第二行math.add(2, 3),在第一行require(‘math’)之后运行,因此必须等math.js加载完成。也就是说,如果加载时间很长,整个应用就会停在那里等。
这对服务器端不是一个问题,因为所有的模块都存放在本地硬盘,可以同步加载完成,等待时间就是硬盘的读取时间。但是,对于浏览器,这却是一个大问题,因为模块都放在服务器端,等待时间取决于网速的快慢,可能要等很长时间,浏览器处于"假死"状态。
因此,浏览器端的模块,不能采用"同步加载"(synchronous),只能采用"异步加载"(asynchronous)。这就是AMD规范诞生的背景。
AMD
AMD是"Asynchronous Module Definition"的缩写,意思就是"异步模块定义"。它采用异步方式加载模块,模块的加载不影响它后面语句的运行。所有依赖这个模块的语句,都定义在一个回调函数中,等到加载完成之后,这个回调函数才会运行。
AMD也采用require()语句加载模块,但是不同于CommonJS,它要求两个参数:
require([module], callback);
第一个参数[module],是一个数组,里面的成员就是要加载的模块;第二个参数callback,则是加载成功之后的回调函数。如果将前面的代码改写成AMD形式,就是下面这样:
require(['math'], function (math) {
math.add(2, 3);
});
主要有两个Javascript库实现了AMD规范:require.js和curl.js。
layui.js外层沙箱以及命名空间$
;!(function(win) {
//用一个函数域包起来,就是所谓的沙箱
//在这里边var定义的变量,属于这个函数域内的局部变量,避免污染全局
//把当前沙箱需要的外部变量通过函数参数引入进来
//只要保证参数对内提供的接口的一致性,你还可以随意替换传进来的这个参数
"use strict";
win.layui = new Layui();
})( window );
是表示使用javascript的严格模式,对于低级的浏览器,这里相当一字符串,所以兼容性是没问题的,详细的话,在阮一峰的文章Javascript 严格模式详解有介绍。
通过定义一个匿名函数,创建了一个“私有”的命名空间,该命名空间的变量和方法,不会破坏全局的命名
空间。这点非常有用也是一个JS框架必须支持的功能。
通过传入window变量,使得window由全局变量变为局部变量,当在layui代码块中访问window时,不
需要将作用域链回退到顶层作用域,这样可以更快的访问window;
layui.js中的框架代码
;!(function(win) {
"use strict";
Layui = function(){
this.v = '2.X'; //版本号
}
//定义组件
Layui.prototype.define = function(deps, factory){
callback = function(){
factory(function(app, exports){
setApp(app, exports);
//此处给layui继续挂载变量,增加callback数组属性,记录每个模块的回调函数
config.callback[app] = function(){
factory(setApp);
}
});
};
//把相关组件加载
that.use(deps, callback, null, 'define');
};
Layui.prototype.use = function(apps, callback, exports, from){
var item = apps[0]
function onScriptLoad(e, url){
head.removeChild(node);
config.status[item] ? onCallback() : setTimeout(poll, 4);
};
function onCallback(){
//此处问号表达式,多于1个app时,调用自己,进入递归调用
apps.length > 1 ? that.use(apps.slice(1), callback, exports, from):
if(typeof layui.jquery === 'function' && from !== 'define'){
return layui.jquery(function(){
callback.apply(layui, exports);
});
};
callback.apply(layui, exports);
};
//apps中的模块已经加载时
if( apps.length === 0 || (layui['layui.all'] && modules[item]) ){
return onCallback(), that;
}
//首次加载模块
if(!config.modules[item]){
//创建script的标签,追加到head中,同时绑定消息
var node = doc.createElement('script');
head.appendChild(node);
if(node.attachEvent){
node.attachEvent('onreadystatechange', function(e){
onScriptLoad(e, url);
});
} else {
node.addEventListener('load', function(e){
onScriptLoad(e, url);
}, false);
}
} else {
(function poll() {
onCallback()
}());
}
return that;
};
win.layui = new Layui();
})( window );
以上就是layui中use方法和define方法的框架代码,可参照源码详细思考。
<欢迎大家讨论>