aralejs / aralejs.github.io Goto Github PK
View Code? Open in Web Editor NEW开放、简单、易用的前端基础类库
Home Page: http://aralejs.github.io
License: MIT License
开放、简单、易用的前端基础类库
Home Page: http://aralejs.github.io
License: MIT License
Widget目前的思路是, 提供一定的生命周期, 在创建过程中调用相应模块提供的方法, 来构建出我们的组件.
通过主要有以下几个模块构成
主要有下面几个模块, 其中对应的模块后面会有详细的解释
数据模型. 这个通过对数据的包装提供更灵活的方式进行使用. 目前的主要功能类似于Backbone.
var Model = require('widget').Model;
var model = new Model({
name: 'alipay',
age: 20
});
var name = model.get('name');
模板封装类. 通过提供Model和对应的template.创建出dom对象
var Tpl = require('widget').Template;
var srcNode = Tpl.toDom(tplStr, model);
这个主要也是针对于data-api的一个扩展, 可以根据提供一个Dom元素, 会分析出来相应的数据模型.
<div id="myDropDown">
<a href="#" data-action-trigger="click">say</a>
<div class="content" data-opt-width="200px" data-opt-height="300px">
</div>
</div>
//创建一个parser实例, 并制定过滤属性
var DAParser = require('widget').DAParser.createParser(['opt1', 'action']);
var parserObj = DAParser.parse(srcNode);
//如果我们的srcNode为上面的属性. 那么我们将返回类似下面的对象
/**
parserObj = {
opts: {
width: "200px",
height: "300px"
},
action: {
trigger: "click"
}
}
**/
行为扩展对象, 对我们组件的行为扩展抽象出Action. 后续的行为扩展都会被这个对象进行管理
var action = require('widget').Action();
action.addAction( function(srcNode, widget) {
$(srcNode).click( function() {
widget.show();
});
});
action.applyAll();
widget核心类. 定义组件的基本生命周期, 并在生命周期中相应的阶段去组合上面相关模块的功能, 并提供相应的接口供用户进行扩展.
define('widget', [], function(require, exports, module) {
var Base = require('base');
var Model = require('./model.js');
var Tpl = require('./template.js');
var DAParser = require('./daparser.js');
var Action = require('./action.js');
module.exports = Base.exend({
data-attrs: [],
action: new Action(),
initialize: function(opts) {
this.model = this.initModel(opts);
this.srcNode = opts.srcNode || this.initTemplate(opts);
var parsedObj = DAParser(this.data-arrts).parse(this.srcNode);//子类需要提供覆盖.
this.setOptions(parsedObj.opts);
this.setOptions(opts);
//这里已经初始化完毕, 相关用户配置选项已经获取. 我么可以由用户在这类先扩展一部分操作, 比如
//根据传入的参数, 去初始化其他对象.
this.beforeCreate();
this.parseActions(); //
this.bind();
this.trigger('initialized');
this.postCreate();
},
initModel: function(opts) {
//从初始化opt中找到和Model相关的属性, 来初始化Model
//用户可以自己覆盖, 初始化自己的model
},
initTemplate: function() {
// 从初始化的opt中找到是否有模板相应信息,
},
beforeCreate: function() {
},
parseAction: function(acts) {
//根据从domNode里面parse出来的action, 来形成真正的action.
// 需要子类去覆盖.
},
addAction: function(action) {
//如果当前组件已经初始化, 那么新加入的action, 会被立即执行
this.action.addAction(action)
},
bind: function() {
action.applyAll(this.srcNode, this);
},
postCreate: function() {
//需要子类覆盖. 比如需要把srcNode插入相应的位置, 显示啥的.
}
});
由于涉及的代码比较多,记录在这里比较合适。
base 组件包含三个文件:
class.js -- 提供 OOP
observable.js -- 事件
optionable.js -- 选项
base.js
最常见的使用方式:
Switchable.js:
define(function(require, exports, module) {
var Base = require('base');
var Switchable = Base.extend({
options: {
zIndex: 9999,
size: {
width: 300,
height: 400
}
},
initialize: function(options) {
this.setOptions(options);
},
show: function() {
...
}
});
module.exports = Switchable;
});
Carousel.js:
define(function(require, exports, module) {
var Switchable = require('./switchable');
var Carousel = Switchable.extend({
implements: ['XXable']
options: {
closeBtn: true,
size: {
width: 800,
height: 600
}
},
initialize: function(options) {
this.superclass.initialize.apply(this, arguments);
this.setOptions(options);
},
setContent: function() {
...
}
}, staticProperties);
// Carousel.__meta { id, deps }
// 还可以通过 implement 添加 instance 属性
Carousel.implement({
loadContent: function() {
}
});
module.exports = Carousel;
});
使用实例:
define(function(require, exports, module) {
var Carousel = require('carousel');
var carousel = new Carousel(...);
});
XX.js:
define(function(require, exports, module) {
var Base = require('base');
var XX = Base.Class.create({
inherits: YY,
implements: Base.Observable,
initialize: fn
});
XX.extend / implement
});
无
在原来的版本处理机制是在一个js里面我们已经生成了依赖映射关系, 一般是在${artifactId}-${version}-index.js 文件中. 类似与下面的语句
deps.addDependency('aralex.xbox',['aralex.xbox-1.7.js','aralex.base-1.1.js','arale.class-1.0.js',
'arale.aspect-1.0.js','arale.tmpl-1.0.js','arale.event-1.1.js','arale.fx-1.1.js','arale.dom-1.1.js',
'arale.string-1.0.js','arale.hash-1.0.js','arale.array-1.1.js','arale.base-1.1.js']);
在这个配置文件中我们可以知道aralex.xbox这个moduleId对应的是aralex.xbox-1.7.js这个文件, 后面就是他的依赖关系.
这时候我们的写法 Loader.use('${artifactId}', function(){})
;
但是目前由于整个依赖关系声明到了依赖模块文件本身了(define函数中)目前的写法临时变为了 seajs.use('${artifactId}-${version}.js', function() {})
; 就是我们目前可以不需要这个index.js文件了. 但是我们加载模块的时候必须
指明我们加载的版本和类型. 然后等这个文件加载完成后, 我们在去根据这个文件本身去parse他的依赖关系, 在进行后续的加载和执行. 那看看后续我们如何兼容原有的这个对应关系.
其实应该提供自动处理被 select,flash 等覆盖问题的 Overlay 组件,所有的悬浮组件都可以继承/组合使用该组件。
而不是在每次需要悬浮层的时候,调用这个补丁工具处理。
议题列表:
上半场(测试等人员都参加)一个小时内
下半场(开发留下)一个小时内
参考:
想法:
顺道考虑下 json 模块
昨天的讨论记录,贯高贴过来。
讨论的规范部分,已整理到 Wiki 文档:
请 Arale 项目成员仔细阅读,严格遵守。
已经按照昨天的 code review 修改了一部分。还有些问题:
{ element: xx, x: ..., y: ... }
对内的,可以适当简写,对外的,尽量全称。
src/position.js
的 12 行和 76 行可以在加一个空行,用空行来表示区分大段落。arale/tools/gjslint
, 将报错都解决掉,可用 fixstyle 自动修复。var isIE6 = $.browser.msie && $.browser.version == 6.0;
先继续用 jquery 的,既然提供了,就大胆用。
原来的系分文档:
https://github.com/alipay/arale/issues/22
目前组件的基类已经开发完成。目前面临的几个问题需要讨论?
目前是
由于是所有组件的基类, 所以在命名上面,需要更加慎重。 对于目前的几个命名可能需要进一步讨论。
目前view支持支持组件对应的模板的渲染,和样式的处理, 在这View层上是否需要增加show和hide这些便利的方法?
目前的Action的抽象还没有很好的处理, 这块也是很关键,后续业务的分离很大一部分都需要使用到他。
目前在组件存在两类事件, dom事件,和组件本身的事件, 我们是否把这两类统一为一个接口, 还是想目前这样进行分开?
目前支持提供了基本的几个方法。 那么后续我们是不是可以尽量的来通过模块的方式来混入到组件中来提供相应的功能?
dist目录是打包工具自动生成的,handy如果使用arale组件时必须要使用dist目录中的组件,这样的话在开发handy组件时,就需要手动创建 dist目录,并且把所需的arale组件copy过来,对手动copy没有疑问,但是对在开发过程中手动创建dist目录存在疑问,这样是不是违背了dist目录的构建原则?会不会带来其它的问题?
之前在wiki建了,后来被合并到编码规范中。不过编码规范主要是js写法上的,还有一部分是类库的一个约定,先记录在这里,方便讨论
jquery接下来几个版本可能会去掉jQuery.browser,我们要不要先拆出来,如果用的多了可能比较难拆了。
或者可以自己写,借鉴太伯以前写的
今天在写storage时,向window注册了一个storage事件,用于监听数据存储,由此联想到一个问题,如果用户不小心从window移除了这个事件,我的storage就没有办法正常工作了。因此想到了jquery的事件命名空间$.bind('click.cashier',callback)。。
Events是否提供事件命名空间?还是使用通用类库提供的事件命名空间?
昨天的讨论中提到handy Stoarge的deleteKey可以修改为Storage.delete,最后测试了一把,在pc端没有报错,但在移动平台却抛出一个Parse error异常,所以只能再改回Storage.deleteKey
srcNode是以jQuery对象或Zepto对象传入还是以原始dom对象传入还是以选择器传入?这个问题似乎之前没有确定。
var overlay = new Overlay({
srcNode: $('#J-login-overlay') / document.querySelector('#J-login-overlay') / '#J-login-overlay'
})
我理解的是 Base 就应该是最简单的一个面向对象的框架,Events 属于事件驱动设计。将这两者揉到一起感觉很别扭。这个设计,包括默认集成 options,和 arale 的 simple 原则 不一致。
如果说 this.parent() 是语法糖,那 options 实际上也是,况且 options 式的函数风格虽然好,但不一定适合每个人的习惯,甚至说和团队习惯、原有代码都有可能冲突。而且有的类可能第一个参数就是 options,类似 Backbone.View
。
我觉得像 Backbone 一样让开发者来选择是否混入 Events 和 Options 是比较好的做法。
像arale.array,arale.dom等模块应该如何组织?
针对现在已经改动的模块,存在以下问题:
我的观点,要么直接不使用define,把代码整好,最后整个arale通过一个define来完成模块的封装,要么使用define,每个模块都严格遵循规范,为了达到与现在兼容,在arale.core进行组装,API封装等。
倾向于第二种。
backbone 已经采纳了 @lifesinger events 的实现方案,性能很棒;发现了个小问题,已提交给 backbone 了
jashkenas/backbone#1310
do not modify
事件这块的扩展和jquery接口尽量保持一致. 主要功能也是在Jquery的事件基础上进行扩展.
需要有关事件发布的场合都可以使用. 目前主要通过混入的方式. 在Widget默认会混入此对象. 所以只要继承与Widget的组件, 默认都会包含此功能.
一边研究一边记录。
Ember.js 的目的有两点:
与 web pages 不同,web pages 每次刷新都需要从浏览器端去重新请求数据。
与 ajax 也不同,在页面中有多处需要更新时,ajax 要维持 UI 与数据的同步很麻烦。
Ember.js 希望:
Ember.js 有三个核心功能:
功能 3 是我们最感兴趣的。(我们想让后端来写前端代码,前端只需提供开发模式、组件库、样式等前端工作,业务代码尽量让后端通过 js 能自己完成)
预定时间:14:30 - 17:00
预定地点:义誉钱庄
议题:
template 组件初步决定选用 handlebars
先提个issue,大家有什么建议回在这里
源码:https://github.com/alipay/arale/blob/master/lib/position/src/position.js
pin 方法背后的抽象模型很好,赞。
如题。
在 options.js 中有这样一段代码
function merge(receiver, supplier) {
var key, value;
for (key in supplier) {
value = supplier[key];
if (typeof value === 'object') {
value = merge(receiver[key] || {}, value);
}
receiver[key] = value;
}
return receiver;
}
这样导致数组被转换成 object 了。遇到DOM对象也进行深度copy的时候就悲剧了。
请修复.
定义类的接口和backbone的基本一致,是要单独再实现一次,还是直接引用对backbone的依赖?
Arale 2.0 进入火热编码第二周,目前已完善基本的架构设计文档:
Arale 2.0 已开发完成的组件,目前已达 13 个,包括:
还有两个组件快开发完毕,欢迎 code review:
开发中的组件还有:widget, overlay, switchable, dropdown 等等,欢迎阅读 README, 现在就给我们建议。
所有组件源码地址:https://github.com/alipay/arale/tree/master/lib
本周还就编码规范、注释风格等问题,在内部和社区进行了热烈讨论,最后形成的规范请看:
https://github.com/alipay/arale/wiki 里,开发规范部分
最后,感谢所有参与讨论的朋友们。因为有大家在一起,我相信 Arale 2.0 一定会越来越好。
postion & widget 现在还是依赖 jQuery,Handy 这边有些 UI 组件要使用它们。麻烦 @lifesinger 或谁能否改一下
DATA-ATTRIBUTE API 是一套 API 风格约定,遵循该风格约定的 Widget 组件,都可以直接从 Markup 初始化。
以 Tabs 为例:
<div data-widget-type="Tabs" data-widget-options="{ }">
<ul>
<li data-widget-role="trigger">1</li>
<li data-widget-role="trigger">2</li>
<li data-widget-role="trigger">3</li>
</ul>
<div data-widget-role="panel">内容块</div>
<div data-widget-role="panel">内容块</div>
<div data-widget-role="panel">内容块</div>
</div>
目前有一种情况就是,我们可能有多级继承, 那么子类有没有便捷的方法从祖先类上面继承下来options?
目前是在子类是通过遍也是可以处理的。但是这样还是有点不太方便啊。
seajs.use(['jquery', 'base'], function($, Base) {
console.log(Base);
var Person = Base.extend({
options: {
o1: 'p1',
o2: 'p2',
o3: 'p3'
},
initialize: function(options) {
this.setOptions(options);
console.log('person initialize');
}
});
var Man = Person.extend({
options: {
o3: 'm1',
o4: 'm2'
},
initialize: function(options) {
Man.superclass.initialize.apply(this, arguments);
console.log('Man initialize');
this.setOptions(options);
}
});
var Child = Man.extend({
options: {
o4: 'C1',
o5: 'C2'
},
initialize: function(options) {
//Child.superclass.initialize.apply(this, arguments);
console.log('Child initialize');
this.mergeSuperOptions(options); //手动遍历?
this.setOptions(options);
},
mergeSuperOptions: function(options) {
var _super = Child.superclass;
var _options;
while(_super) {
if (_super.options) {
_options = _super.options;
for (var key in _options) {
if (_options.hasOwnProperty(key) && (!(key in options))) {
options[key] = _options[key]
}
}
}
_super = _super.constructor.superclass;
}
}
});
var c = new Child({o4: 'mm1'});
console.log(c.options);//如果默认{ o4="mm1", o5="C2"}. 通过merge 也就是我们期望的{o1:'p1', o2: 'p2', 'o3': 'm1', 'o4': 'mm1', 'o5': 'C2'}
});
冒顿:
话说我一直希望 form validator 使用 webform2 的方式
参考
广告语:自从有了众望所归的框架和规范,贡献代码也有劲了!熬夜也不黑眼圈了! XD
将 events
, class
, options
从 base
中独立出来后,面临一个问题:
define(function(require) {
var Events = require('events');
function MyClass() { ... }
// 如何将 Events 提供的功能,混入到 MyClass 中?
});
一种方式是,再引入 class
或 base
模块,然后通过 Class.create
或 Base.extend
中的 Implements
属性来指定混入 Events
:
define(function(require) {
var Events = require('events');
var Class = require('class');
var MyClass = Class.create({
Implements: Events,
...
});
});
但对于很多工具类,比如 Position 或无线端的 Storage 等来说,并不是 function class, 用 Class.create
来创建意义不大。这种情况下,传统的一个解决思路是:
define(function(require) {
var Events = require('events');
var seed = require('seed');
var Storage = {
set: ...
get:...
};
// 通过 seed 或某个类,来提供 mix 等方法
// 或者自己在 Storage 中实现一个 mix 方法
seed.mix(Storage, Events.prototype);
});
很显然,通过 seed 或 util 等思路来解决,比较适合 YUI, KISSY 等一站式类库(可以直接放在 Y 和 S 中)。但对 Arale 的思路来说,这并不妥。Arale 没有所谓的 seed 或 core,要按上面的思路去做的话,会导致 Events
在使用时,得强依赖另一个 util 或 seed 组件,然而很可能仅仅只用到一个 mix 方法。
这个问题与颂赞等人讨论过,无线端不少工具类组件需要 Events,并不需要 Class 和 Base.
这问题一直萦绕心头,今天偶然看到一篇技术文章里提到 IoC(控制反转),莫名就联想到了这个问题,而且发现 jQuery 的 appendTo
等方法也有类似的意思,因此就想到:
不如让 Events 自己提供 mixTo 方法
立刻感觉云散花开,很自然的就可以:
define(function(require) {
var Storage = {
set: ...
get:...
};
// 让 Storage 方法拥有 on/off/trigger
require('events').mixTo(Storage);
return Storage;
});
代码明显精简、漂亮多了。更重要的是,让 Storage 的依赖减少,更解耦了。
想起陈皓的一篇文章:http://coolshell.cn/articles/7236.html
解耦,解耦,解耦。
Arale 类库的设计**里,也有一段很重要的:
不追求代码的零重复,更追求组件的独立性。
如果大家认可,我觉得接来下我们可以进一步约定,凡是可以 mix 给普通对象(比如 var obj = {}
)用的组件,比如 Events 这种,默认应该都提供 mixTo
方法。
源码:https://github.com/alipay/arale/tree/master/lib/iframe-shim
var Shim = require('iframe-shim');
var shim = new Shim(targetElement);
shim.sync(); // 第一次同步也交给开发者自己控制
show 和 hide 是否没必要了,开发者有 sync 就搞定了一切。
另外,感觉需要增加一个 destroy 方法,用来销毁创建的 iframe.
比如 overlay 里:
var Overlay = Widget.extend({
initialize: function(srcNode) {
// overlay 里只需要下面这句
// 等以后 ie6 退出历史舞台了,只需删除这一句,和 initShim 方法就行
this.initShim(srcNode);
},
initShim: function(srcNode) {
var Shim = require('iframe-shim');
var shim = new Shim(srcNode);
this.on('show hidden', shim.sync);
this.on('destroy', shim.destroy);
}
});
http://www.quchao.com/entry/detect-browser-by-features/
(function (win, doc) {
var isIE = !+'\v1', // alt: !!-[1,]
isIE6 = isIE && !('maxHeight' in doc.body.style),
isIE8 = isIE && 'prototype' in Image,
isIE7 = isIE && !isIE6 && !isIE8,
//isIE9 = isIE && .1 === +(.09).toFixed(1),
isFF = !!doc.getBoxObjectFor || 'mozInnerScreenX' in win, // gecko
isOP = !!win.opera && !!win.opera.toString().indexOf('Opera'),
isOP9 = /^function \(/.test([].sort),
isWK = !!win.devicePixelRatio, // web-kit
isSF = /a/.__proto__ == '//', // safari
isCR = /s/.test(/a/.toString); // chrome
})(window, document);
useIframe 或许直接叫 isIE6 更简单直白
$.browser 能不用则不用
$(target).after(iframe)
心存质疑,或许直接插入到 body 中更好。target 有可能还没在 dom 树里,另外可能层级很深,放在之后,对性能有影响。xx.prototype = {}
的写法,会搞掉 constructoris(':hidden')
已经包含了高宽为 0position.pin
应该放在 this.show()
前面,都准备好后,再显示。define(function(require, exports, module) {
function Shim() {
}
Shim.prototype.sync = ...
Shim.prototype.destroy = ...
if (isIE6) {
module.exports = Shim;
} else {
function noop() {
}
noop.prototype.sync = noop;
noop.prototype.destroy = noop;
module.exports = noop;
}
});
大讨论呀大讨论,JSDoc 有无必要。show 和 hide 这种方法的注释,实在是冗余呀。
如无必要,勿增注释。如有必要,注释勿少。
以 events 的为模板
文档书写风格讨论,中西文之间的空格。
挺不错的,test 里面的 Test 字符可以去掉。
真实代码与 pre code 的同步问题。
目前 backbone 和 position 两个模块,源码里都有:
var $ = require('jquery');
打包后,在各自 deps 里,都添加上了 jquery 硬字符串。对移动端开发来说,需要再将 jquery 替换成 zepto, 麻烦。
我们是否可以约定,如果一个模块满足以下两点:
则在引用 DOM 操作类库时,必须采用以下写法:
var $ = require('$');
$ 的具体取值,由外部配置决定,比如在 arale 里,是:
seajs.config({
alias: {
'$': 'jquery/1.7.2/jquery'
}
});
在 handy 里,则是:
seajs.config({
alias: {
'$': 'zepto/0.8.0/zepto'
}
});
这在开发时,比较舒适了,测试也方便,切换 alias 就可以切换场景。
带来的问题是,我们之前的打包策略要求打包后的信息是完备的,不依赖开发时的 alias 配置,也就是打包后要生成两份不同的文件:
define('#backbone/0.9.2/backbone', ["#jquery/1.7.2/jquery", ...], ...);
define('#backbone/0.9.2/backbone', ["#zepto/0.8.0/zepto", ...], ...);
这两份文件,共用的 id 是同一个,这和 id 与文件名一致的约定冲突。我想到的解决办法是,backbone 打包后,生成两份文件:
dist/backbone/0.9.2/backbone.js
dist/backbone/0.9.2/backbone-mobile.js
内容分别是:
define('#backbone/0.9.2/backbone', ["#jquery/1.7.2/jquery", ...], ...);
define('#backbone/0.9.2/backbone-mobile', ["#zepto/0.8.0/zepto", ...], ...);
这要求移动端开发时,引入 backbone 时加上 mobile 标识:
var BB = require('backbone-mobile');
PC 端依旧是 require('backbone')
大家看看上面的方案是否有考虑不周的地方,欢迎提建议。
利用业界现有的解决方式:
这两种,需要前后通吃的 Web Developer 来达成。在阿里,目前很难。
核心是:解藕,让更合适的人做更合适的事。
目前 Arale 的发展方向,可以很好的支撑:
目前 Arale 没想清楚如何支撑第三种模式:
还有一个很现实的问题,如果体验类的研发模式可行,意味着要投入大量前端资源去做,这对产品是利好的,但这一研发模式,很可能会加剧前端的资源瓶颈问题。有无可能培养后端成为体验类的前端开发?让部分后端也可以独立承担开发?
越想越觉得迷茫,我们期待的研发模式,究竟靠不靠谱?如果要做,具体究竟该如何做?
集思广益,大家发表点建议。
考虑封装 swfobject 还是自己开发
若有更好的选择,欢迎推荐
---arale.event
--------resources
------------event.js
------------core.js
------------object.js
------------store.js
------------chain.js
--------pom.xml
define(function(require, exports) {
require('./object');
require('./store');
var chain = require('./chain');
var core = require('./core');
//如果主模块要暴漏子模块的接口, 可以使用
exports.connect = core.connect;
mixin(chain, module.exports); // 将某个子模块的所有对外接口 添加到父模块中
});
define(function(require, exports) {
var arr = require('arele.array');
//.........代码
exports.object = function() {};
});
define(function(require, exports) {
var hash = require('arele.hash');
//.........代码
exports.store = function() {};
});
define(function(require, exports) {
var base = require('arele.base');
//.........代码
exports.chain = function() {};
});
define(function(require, exports) {
var arr = require('arele.array');
var eo = require('./object');
var store = require('./store');
//.........代码
exports.connect = function() {};
});
arele.event-2.0-src.js
define('arale.event-2.0', ['arale.dom-1.1', 'arale.array-1.1', 'arale.hash-1.1', 'arale.base-1.1'], function(require, exports, module) {
require('arale.event-object-2.0');
require('arale.event-store-2.0');
var chain = require('arale.event-chain-2.0');
var core = require('arale.event-core-2.0');
//如果主模块要暴漏子模块的接口, 可以使用
exports.connect = core.connect;
mixin(chain, module.exports); // 将某个子模块的所有对外接口 添加到父模块中
});
define('arale.event-object-2.0', ['子模块的dependency由于他的运行是建立在主模块上的, 所以是空的'], function(require, exports, module) {
var arr = require('arele.array-1.1');
//.........代码
exports.object = function() {};
});
define('arele.event-store-2.0', [], function(require, exports) {
var hash = require('arele.hash-1.1');
//.........代码
exports.store = function() {};
});
define('arale.chain-2.0', [], function(require, exports) {
var hash = require('arele.hash-1.1');
//.........代码
exports.store = function() {};
});
define('arale.core-2.0', [], function(require, exports) {
var arr = require('arele.array-1.1');
var eo = require('arale.event-object-2.0');
var store = require('./store');
//.........代码
exports.connect = function() {};
});
我们之前考虑核心和组件的改造,之后考虑下系统代码按照现有的改造还是需要个性化。由于使用较广,尽量兼容现有场景,避免大范围的改造。
由于模块化后都是在毕包内执行的,如果发现线上问题很难及时处理。应可虑一个方案可以快速处理问题。
把要写的组件列在这里吧
下面的目录主要设计源代码和打包后需要存放等目录
arale/
-- dist/
-- xxx/1.0.0/..
-- lib/
-- xxx/
-- src/
-- __config.js
-- widget.js
-- view.js
-- model.js
-- base.css
-- /
static/
-- js/
-- base/
-- src/
-- __config.js
-- base.js
-- cahser.js
-- personal.js
-- sites/
-- bj.js
-- hz.js
-- sh.js
-- /
-- module/
-- css
-- base/
-- release # 含义同 dist
/tmp
临时目录. 当我们在文件在打包过程中对源文件进行依赖分析, 映射替换, 变量替换等操作后, 文件存储的位置. 里面的文件下面我们将以一个系统项目为例子, 说明相关打包流程,和打包后的文件变化情况, 以及相关部署的操作.
/** __config.js **/
/** 相关不重要的已被省略, 具体的配置参看相关文档**/
define({
………..
"version": '1.0.1-dev',
"parent": '/config/cashier/1.1.0/',
"alias": {
'_': 'ar/underscore/0.9.2/underscore.js',
'xbox': 'ar/xbox/2.0/xbox.js',
'sec': 'cashier/1.2/security/'
},
"dist": {
'cashier.js': ['cashier.js', 'base.js'], // 在dist目录产生a.js, 并把b.js, c.js, d.js打包合并到a.js中
'personal.js': ['personal.js', 'base.js']
'sites': ['sites/*.js']
}, // 文件产生策略. 根据这个配置来确定对外部署的文件.
"repository": "http://alipay.im/arale2/repos/",
});
/** cashier.js **/
define(function(require, exports, module) {
var xbox = require('xbox');
var base = require('./base');
var a = require('sec/a.js');
var b = require('sec/b.js');
exports.doSth = function() {
//.…..
};
});
/** personal.js **/
define(function(require, exports, module) {
var _ = require('_');
var base = require('./base');
exports.doSth = function() {
//.…..
};
});
/** base.js **/
define(function(require, exports, module) {
var jquery = require('jquery');
exports.doSth = function() {
//.…..
};
});
其中我们在打包后主要关注的就是dist目录的情况. 这个目录中内容主要是根据在 __config.js 中的配置来确定的. 下面就列出了按照上面的配置, 我们这个目录的相关内容, 和源码的变化.
/
-- /base/1.0.1-dev/cashier.js
-- /base/1.0.1-dev/personal.js
-- /base/1.0-1-dev/sites/
-- bj.js
-- hz.js
-- sh.js
/** cashier.js
define('#cashier/base/1.0.1-dev/cashier.js', ['#casier/base/1.0.1-dev/base.js','#ar/jquery/1.7.2/jquery.js', '#ar/xbox/2.0/xbox.js', '#ar/widget/2.0/widget.js', '#ar/oo/2.0/class.js'], function(require, exports, module) {
var xbox = require('#ar/xbox/2.0/xbox.js');
var base = require('#cashier/1.0.1-dev/base.js');
var a = require('#cashier/1.2/security/a.js');
var b = require('#cashier/1.2/security/b.js');
exports.doSth = function() {
//.…..
};
});
//base.js被合并进来了.
define('#cashier/base/1.0.1-dev/base.js', ['#ar/jquery/1.7.2/jquery.js'], function(require, exports, module) {
var jquery = require('#ar/jquery/1.7.2/jquery.js');
exports.doSth = function() {
//.…..
};
});
/** personal.js **/
define('#cashier/base/1.0.1-dev/personal.js', ['/casier/base/1.0.1-dev/base.js', '/ar/underscore/0.9.2/underscore.js', '/ar/jquery/1.7.2/jquery.js'], function(require, exports, module) {
var _ = require('#ar/underscore/0.9.2/underscore.js');
var base = require('#cashier/1.0.1-dev/base.js');
exports.personal = function() {
//.…..
};
});
//base.js被合并进来了.
define('/cashier/base/1.0.1-dev/base.js', ['/ar/jquery/1.7.2/jquery.js'], function(require, exports, module) {
var jquery = require('/ar/jquery/1.7.2/jquery.js');
exports.doSth = function() {
//.…..
};
});
/** sites/下面的文件由于是资源文件, 没有变化. **/
其中在上面需要注意的是:
把dist目录中的文件发布到相应位置即可. 比如在这里. 我们可以把dist中的目录传递到线上cashier/下面
action
seajs.use('/cashier/base/1.0.1{-dev}/base.js', function(base) {
base.cashier();
});
//
//在这里{-dev}在seajs.use的时候会去检查当前页面所在环境, 如果线上会-dev会被替换为'', 而在测试环境始终请求的是-dev.
// 其中需要理解的时候当1.0.1版本发布后这两个版本对应的模块文件是等价的(1.0.1-dev.js == 1.0.1.js)
主要就是对模块在页面中的注册和查找的兼容性处理.
组件名 类别
device util
network util
iscroll util
pintostart util
floatlayer util
slider widget
touchslider widget
swap widget
flip widget
touch widget
touchview widget
datalist biz
datafilter biz
paychannel biz
bizswitch biz
在arale.dom中, 依赖arale.event的接口, arale.event也依赖arale.dom中的接口.
仅判断是否为 ie6 一项:
position 用的是 $.browser.msie && $.browser.version == 6.0
iframe-shim 用的是 !-[1,] && !('maxHeight' in document.body.style)
,这个过不了 gjslint
而我习惯用 !!window.VBArray && !window.XMLHttpRequest
加上这个组件后,统一掉所有的地方。
@lifesinger 不是组员选不了 label,难怪右栏空白一片~ ^_^
看了下大家的代码,为了保证整体风格一致,有些地方需要达成一致:
如果是纯声明,或非常简短的赋值,可以写成一行。比如:
var cache, event, all, list, i, len, rest = [], args;
如果赋值语句较长,目前有一种写法是用逗号换行:
var $ = require('jquery'),
position = require('position'),
useIframe = $.browser.msie && Number($.browser.version) < 7;
还有一种写法是直接用 var
风格:
var $ = require('jquery');
var position = require('position');
var useIframe = $.browser.msie && Number($.browser.version) < 7;
我建议直接用 var
风格呀,这样无论写起来还是修改都更方便,用 closure compiler 等压缩后,会自动变成上面那种逗号分隔的。
没记错的话,前面那种逗号风格的兴起,是 NCZ 在2009 年介绍 YUI Compressor 压缩原理时提到的:
http://www.slideshare.net/nzakas/extreme-javascript-compression-with-yui-compressor
NCZ 倡导:为了帮助压缩工具实现更好的压缩,倡导一个函数内,尽量只保持一个 var
和 return
.
然而,目前高级压缩器,Closure Compiler 和 UglifyJS 等,都能自动处理 var
了,在压缩函数时,会自动做变量提升和 var 单一化。
因此尽量保持一个 var 的最佳实践,目前已不是最佳实践。大方向肯定是更人性化、更自然化的写法。优化交给工具就好。
最后,强烈建议:多个 var
, 且非纯声明或简单赋值时,建议写成:
var $ = require('jquery');
var position = require('position');
var useIframe = $.browser.msie && Number($.browser.version) < 7;
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.