Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
KISSY.Base - all about that Base
Search
Sponsored
·
Your Podcast. Everywhere. Effortlessly.
Share. Educate. Inspire. Entertain. You do you. We'll handle the rest.
→
ningzbruc
August 06, 2015
Programming
130
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
KISSY.Base - all about that Base
KISSY.Base的设计方法和最佳实践
ningzbruc
August 06, 2015
More Decks by ningzbruc
See All by ningzbruc
如何写出一个优秀的开源库
ningzbruc
0
66
去啊无线前端的一天
ningzbruc
1
180
React & Component
ningzbruc
0
45
阿里旅行去啊H5首页总结&Promise
ningzbruc
0
270
Hammer.js
ningzbruc
1
340
淘宝旅行门票iPad版开发
ningzbruc
0
140
Travel on KISSY mini
ningzbruc
0
200
Events
ningzbruc
2
130
Why YUI3
ningzbruc
0
190
Other Decks in Programming
See All in Programming
ユニットテストの先へ:テスト技法で要求・仕様を整理するJava開発実践 / Beyond_Unit_Testing_Practical_Java_Development_Techniques_for_Organizing_Requirements_and_Specifications
shimashima35
0
390
Signal Forms: Beyond the Basics @ngBaguette 2026 in Paris
manfredsteyer
PRO
0
240
DynamoDBには集計系のクエリがないけどなんとかしたい
musan
1
130
OSもどきOS
arkw
0
480
AutonomyとControlのあいだ:Graflowで記述するAIエージェント協調
myui
0
120
正しくソフトウェアを作る、前提を疑うための認知の視点 / doubt-premise
minodriven
20
6.4k
Oxlintのカスタムルールの現況
syumai
6
1.1k
Lemonade + Foundry Toolkit でお手軽アプリ開発
seosoft
1
320
Modding RubyKaigi for Myself
yui_knk
0
910
These Five Tricks Can Make Your Apps Greener, Cheaper, & Nicer
hollycummins
0
280
AIとASP.NET Coreで雑Webアプリを作った話
mayuki
0
500
生成AI時代にこそ効くGo | Why Go Works in the Age of Generative AI
mom0tomo
8
3.2k
Featured
See All Featured
I Don’t Have Time: Getting Over the Fear to Launch Your Podcast
jcasabona
34
2.8k
Ecommerce SEO: The Keys for Success Now & Beyond - #SERPConf2024
aleyda
1
2k
The Invisible Side of Design
smashingmag
302
52k
Stop Working from a Prison Cell
hatefulcrawdad
274
21k
WENDY [Excerpt]
tessaabrams
11
38k
Rebuilding a faster, lazier Slack
samanthasiow
85
9.5k
Intergalactic Javascript Robots from Outer Space
tanoku
273
27k
Why Our Code Smells
bkeepers
PRO
340
58k
Why Mistakes Are the Best Teachers: Turning Failure into a Pathway for Growth
auna
0
160
DBのスキルで生き残る技術 - AI時代におけるテーブル設計の勘所
soudai
PRO
65
55k
Principles of Awesome APIs and How to Build Them.
keavy
128
17k
How to build a perfect <img>
jonoalderson
1
5.6k
Transcript
纗䔺 ⚜⠫
None
Base • 组件标准化 • 继承与组合
#1 组件标准化
⼀一个简单组件的三要素 • ⽣生命周期(LifeCycle) • 参数配置(Config) • 事件通信(Event)
# Example - Box
API var box = new Box({ content: 'this is a
box!', parent: '#container', onShow: function() { alert('visible'); } }); box.show(); box.hide(); box.destroy(); # Example - Box
-JGF$ZDMF ളଁᇛ௹ var box = new Box({ content: 'this is
a box!', parent: '#container', onShow: function() { alert('visible'); } }); box.show(); box.hide(); box.destroy(); # Example - Box
$POGJH ҕඔᇂ var box = new Box({ content: 'this is
a box!', parent: '#container', onShow: function() { alert('visible'); } }); box.show(); box.hide(); box.destroy(); # Example - Box
&WFOU ൙ࡱ๙ྐ var box = new Box({ content: 'this is
a box!', parent: '#container', onShow: function() { alert('visible'); } }); box.show(); box.hide(); box.destroy(); # Example - Box
/** * 构造函数 */ function Box() { this.init.apply(this, arguments); }
/** * 原型 */ Box.prototype = { /** * 构造函数 */ constructor: Box, /** * 初始化 */ init: function() { /* ... */ }, /** * 销毁 */ destroy: function() { /* ... */ } }; -JGF$ZDMF ളଁᇛ௹ Step 1
Step 1 /** * 初始化 */ init: function() { this.render();
}, /** * 渲染 */ render: function() { this.box = document.createElement('div'); this.box.style.display = 'none'; this.box.innerHTML = this.cfg.content; this.cfg.parent.appendChild(this.box); }, /** * 销毁 */ destroy: function() { this.cfg.parent.removeChild(this.box); this.cfg = null; this.box = null; } -JGF$ZDMF ളଁᇛ௹
/** * 初始化 */ init: function() { this.config(cfg); this.render(); },
/** * 参数配置 */ config: function(cfg) { cfg = cfg || {}; cfg.parent = typeof cfg.parent == 'string' ? document.querySelector(cfg.parent) : cfg.parent; this.cfg = mix({ content: '', parent: document.body }, cfg); }, $POGJH ҕඔᇂ Step 2
/** * 初始化 */ init: function() { this.config(cfg); this.render(); },
/** * 参数配置 */ config: function(cfg) { cfg = cfg || {}; cfg.parent = typeof cfg.parent == 'string' ? document.querySelector(cfg.parent) : cfg.parent; this.cfg = mix({ content: '', parent: document.body }, cfg); }, Step 2 ਅݺ֥࡙ಸྟ
/** * 展⽰示 */ show: function() { this.box.style.display = 'block';
this.cfg.onShow && this.cfg.onShow.call(this); } Step 3 &WFOU ൙ࡱ๙ྐ
Problems?
/** * 初始化 */ init: function() { this.config(cfg); this.render(); },
/** * 参数配置 */ config: function(cfg) { cfg = cfg || {}; cfg.parent = typeof cfg.parent == 'string' ? document.querySelector(cfg.parent) : cfg.parent; this.cfg = mix({ content: '', parent: document.body }, cfg); }, َ෫֥ҕඔᇂ Step 2
buildParam : function(o) { var that = this; var o
= ( typeof o == 'undefined' || o == null) ? {} : o; that.autoSlide = ( typeof o.autoSlide == 'undefined' || o.autoSlide == null) ? false : o.autoSlide; that.speed = ( typeof o.speed == 'undefined' || o.speed == null) ? 0.5 : o.speed; that.timeout = ( typeof o.timeout == 'undefined' || o.timeout == null) ? 1000 : o.timeout; that.timedelay = ( typeof o.timedelay == 'undefined' || o.timedelay == null) ? -1 : o.timedelay; that.effect = ( typeof o.effect == 'undefined' || o.effect == null) ? 'none' : o.effect; that.eventype = ( typeof o.eventype == 'undefined' || o.eventype == null) ? 'click' : o.eventype; that.easing = ( typeof o.easing == 'undefined' || o.easing == null) ? 'easeBoth' : o.easing; that.hoverStop = ( typeof o.hoverStop == 'undefined' || o.hoverStop == null) ? true : o.hoverStop; that.selectedClass = ( typeof o.selectedClass == 'undefined' || o.selectedClass == null) ? 'selected' : o.selectedClass; that.conClass = ( typeof o.conClass == 'undefined' || o.conClass == null) ? 't-slide' : o.conClass; that.navClass = ( typeof o.navClass == 'undefined' || o.navClass == null) ? 'tab-nav' : o.navClass; that.contentClass = ( typeof o.contentClass == 'undefined' || o.contentClass == null) ? 'tab-content' : o.contentClass; that.pannelClass = ( typeof o.pannelClass == 'undefined' || o.pannelClass == null) ? 'tab-pannel' : o.pannelClass; that.before_switch = ( typeof o.before_switch == 'undefined' || o.before_switch == null) ? new Function : o.before_switch; that.ready = ( typeof o.ready == 'undefined' || o.ready == null) ? new Function : o.ready; that.carousel = ( typeof o.carousel == 'undefined' || o.carousel == null) ? false : o.carousel; that.id = that.id; that.tabs = []; that.animcon = null; that.pannels = []; that.timer = null; that.defaultTab = ( typeof o.defaultTab == 'undefined' || o.defaultTab == null) ? 0 : Number(o.defaultTab) - 1; that.current_tab = that.defaultTab; return this; },
buildParam : function(o) { var that = this; var o
= ( typeof o == 'undefined' || o == null) ? {} : o; that.autoSlide = ( typeof o.autoSlide == 'undefined' || o.autoSlide == null) ? false : o.autoSlide; that.speed = ( typeof o.speed == 'undefined' || o.speed == null) ? 0.5 : o.speed; that.timeout = ( typeof o.timeout == 'undefined' || o.timeout == null) ? 1000 : o.timeout; that.timedelay = ( typeof o.timedelay == 'undefined' || o.timedelay == null) ? -1 : o.timedelay; that.effect = ( typeof o.effect == 'undefined' || o.effect == null) ? 'none' : o.effect; that.eventype = ( typeof o.eventype == 'undefined' || o.eventype == null) ? 'click' : o.eventype; that.easing = ( typeof o.easing == 'undefined' || o.easing == null) ? 'easeBoth' : o.easing; that.hoverStop = ( typeof o.hoverStop == 'undefined' || o.hoverStop == null) ? true : o.hoverStop; that.selectedClass = ( typeof o.selectedClass == 'undefined' || o.selectedClass == null) ? 'selected' : o.selectedClass; that.conClass = ( typeof o.conClass == 'undefined' || o.conClass == null) ? 't-slide' : o.conClass; that.navClass = ( typeof o.navClass == 'undefined' || o.navClass == null) ? 'tab-nav' : o.navClass; that.contentClass = ( typeof o.contentClass == 'undefined' || o.contentClass == null) ? 'tab-content' : o.contentClass; that.pannelClass = ( typeof o.pannelClass == 'undefined' || o.pannelClass == null) ? 'tab-pannel' : o.pannelClass; that.before_switch = ( typeof o.before_switch == 'undefined' || o.before_switch == null) ? new Function : o.before_switch; that.ready = ( typeof o.ready == 'undefined' || o.ready == null) ? new Function : o.ready; that.carousel = ( typeof o.carousel == 'undefined' || o.carousel == null) ? false : o.carousel; that.id = that.id; that.tabs = []; that.animcon = null; that.pannels = []; that.timer = null; that.defaultTab = ( typeof o.defaultTab == 'undefined' || o.defaultTab == null) ? 0 : Number(o.defaultTab) - 1; that.current_tab = that.defaultTab; return this; }, 85'
var box = new Box({ content: 'this is a box!',
parent: '#container', onShow: function() { doA(); } }); /** * 展⽰示 */ show: function() { this.box.style.display = 'block'; this.cfg.onShow && this.cfg.onShow.call(this); } Step 3 &WFOU ൙ࡱ๙ྐ
var box = new Box({ content: 'this is a box!',
parent: '#container', onShow: function() { doA(); } }); /** * 展⽰示 */ show: function() { this.box.style.display = 'block'; this.cfg.onShow && this.cfg.onShow.call(this); } Step 3 &WFOU ൙ࡱ๙ྐ window.onload = loadFn; රᄻཌྷ്
var box = new Box({ content: 'this is a box!',
parent: '#container', onShow: function() { doA(); } }); /** * 展⽰示 */ show: function() { this.box.style.display = 'block'; this.cfg.onShow && this.cfg.onShow.call(this); } box.cfg.onShow = function() { doA(); doB(); }; Step 3 &WFOU ൙ࡱ๙ྐ window.onload = loadFn; රᄻཌྷ്
var box = new Box({ content: 'this is a box!',
parent: '#container', onShow: function() { doA(); } }); /** * 展⽰示 */ show: function() { this.box.style.display = 'block'; this.cfg.onShow && this.cfg.onShow.call(this); } var originOnShow = box.cfg.onShow; box.cfg.onShow = function() { originOnShow.apply(this, arguments); doB(); }; Step 3 &WFOU ൙ࡱ๙ྐ window.onload = loadFn; රᄻཌྷ്
var box = new Box({ content: 'this is a box!',
parent: '#container', onShow: function() { doA(); } }); /** * 展⽰示 */ show: function() { this.box.style.display = 'block'; this.cfg.onShow && this.cfg.onShow.call(this); } var originOnShow = box.cfg.onShow; box.cfg.onShow = function() { originOnShow.apply(this, arguments); doB(); }; Step 3 &WFOU ൙ࡱ๙ྐ ൙ࡱگႨ window.onload = loadFn; රᄻཌྷ്
‘Base’ of Base • ⽣生命周期(LifeCycle) • 参数配置(Attribute) • 事件通信(CustomEvent)
Step 1 -JGF$ZDMF ളଁᇛ௹ // 继承Base var Box = Base.extend({
/** * 初始化 */ initializer: function() { this.render(); }, /** * 渲染 */ render: function() { /* ... */ }, /** * 销毁 */ destructor: function() { this.cfg.parent.removeChild(this.box); this.cfg = null; this.box = null; } });
Step 1 -JGF$ZDMF ളଁᇛ௹ // 继承Base var Box = Base.extend({
/** * 初始化 */ initializer: function() { this.render(); }, /** * 渲染 */ render: function() { /* ... */ }, /** * 销毁 */ destructor: function() { this.cfg.parent.removeChild(this.box); this.cfg = null; this.box = null; } }); //初始化 var box = new Box({ /* ... */ }); //销毁 box.destroy();
Step 1 -JGF$ZDMF ളଁᇛ௹ // 继承Base var Box = Base.extend({
/** * 初始化 */ initializer: function() { this.render(); }, /** * 渲染 */ render: function() { /* ... */ }, /** * 销毁 */ destructor: function() { this.cfg.parent.removeChild(this.box); this.cfg = null; this.box = null; } }); //初始化 var box = new Box({ /* ... */ }); //销毁 box.destroy();
Step 2 // 继承Base var Box = Base.extend({ /* ...
*/ }, { /** * 参数配置 */ ATTRS: { parent: { // 默认值 value: document.body, // 校验 validator: function(v) { return !!v; }, //获取 getter: function(v) { return v; }, //设置 setter: function(v) { return typeof v == 'string' ? document.querySelector(v) : v; } } } }); "UUSJCVUF ҕඔᇂ
Step 2 // 继承Base var Box = Base.extend({ /* ...
*/ }, { /** * 参数配置 */ ATTRS: { parent: { // 默认值 value: document.body, // 校验 validator: function(v) { return !!v; }, //获取 getter: function(v) { return v; }, //设置 setter: function(v) { return typeof v == 'string' ? document.querySelector(v) : v; } } } }); "UUSJCVUF ҕඔᇂ var box = new Box({ parent: '#container', }); box.get('parent');
Step 2 // 继承Base var Box = Base.extend({ /* ...
*/ }, { /** * 参数配置 */ ATTRS: { parent: { // 默认值 value: document.body, // 校验 validator: function(v) { return !!v; }, //获取 getter: function(v) { return v; }, //设置 setter: function(v) { return typeof v == 'string' ? document.querySelector(v) : v; } } } }); "UUSJCVUF ҕඔᇂ var box = new Box({ parent: '#container', }); box.get('parent');
Step 2 // 继承Base var Box = Base.extend({ /* ...
*/ }, { /** * 参数配置 */ ATTRS: { parent: { // 默认值 value: document.body, // 校验 validator: function(v) { return !!v; }, //获取 getter: function(v) { return v; }, //设置 setter: function(v) { return typeof v == 'string' ? document.querySelector(v) : v; } } } }); "UUSJCVUF ҕඔᇂ var box = new Box({ parent: '#container', }); box.get('parent');
Step 2 // 继承Base var Box = Base.extend({ /* ...
*/ }, { /** * 参数配置 */ ATTRS: { parent: { // 默认值 value: document.body, // 校验 validator: function(v) { return !!v; }, //获取 getter: function(v) { return v; }, //设置 setter: function(v) { return typeof v == 'string' ? document.querySelector(v) : v; } } } }); "UUSJCVUF ҕඔᇂ var box = new Box({ parent: '#container', }); box.get('parent');
Step 2 // 继承Base var Box = Base.extend({ /* ...
*/ }, { /** * 参数配置 */ ATTRS: { parent: { // 默认值 value: document.body, // 校验 validator: function(v) { return !!v; }, //获取 getter: function(v) { return v; }, //设置 setter: function(v) { return typeof v == 'string' ? document.querySelector(v) : v; } } } }); "UUSJCVUF ҕඔᇂ var box = new Box({ parent: '#container', }); box.get('parent');
Step 2 // 继承Base var Box = Base.extend({ /* ...
*/ }, { /** * 参数配置 */ ATTRS: { parent: { // 默认值 value: document.body, // 校验 validator: function(v) { return !!v; }, //获取 getter: function(v) { return v; }, //设置 setter: function(v) { return typeof v == 'string' ? document.querySelector(v) : v; } } } }); "UUSJCVUF ҕඔᇂ var box = new Box({ parent: '#container', }); box.get('parent');
/** * 展⽰示 */ show: function() { this.box.style.display = 'block';
this.fire('show'); } var box = new Box({ /* ... */ }); box.on('show', doA); box.on('show', doB); box.on('show', doC); Step 3 $VTUPN&WFOU ሱקၬ൙ࡱ
/** * 展⽰示 */ show: function() { this.box.style.display = 'block';
this.fire('show'); } var box = new Box({ /* ... */ }); box.on('show', doA); box.on('show', doB); box.on('show', doC); Step 3 $VTUPN&WFOU ሱקၬ൙ࡱ
/** * 展⽰示 */ show: function() { this.box.style.display = 'block';
this.fire('show'); } var box = new Box({ /* ... */ }); box.on('show', doA); box.on('show', doB); box.on('show', doC); Step 3 $VTUPN&WFOU ሱקၬ൙ࡱ window.onload = loadFn; window.addEventListener('load', loadFn, false); රᄻཌྷ്
# AttributeCore
AttributeCore • 规范化参数配置 • 处理好参数兼容
get/set box.set('parent', '#page'); box.get('parent'); // div#page ѓሙ߄ҕඔ౼ഡᇂٚൔ
// 继承Base var Box = Base.extend({ /* ... */ },
{ /** * 参数配置 */ ATTRS: { /** * ⽗父节点 * @attribute parent * @type HTMLElement * @default document.body */ parent: { /* ... */ }, /** * 内容 * @attribute content * @type String */ content: { /* ... */ } /* ... */ } }); ၂ଢਔಖ ಸၞົ
• value(默认值) • validator(校验器) • getter(获取值) • setter(设置值) • valueFn(默认值函数)
ATTRS
• value(默认值) • validator(校验器) • getter(获取值) • setter(设置值) • valueFn(默认值函数)
ATTRS 常⽤用属性
parent: { // 默认值 value: document.body, // 校验 validator: function(v)
{ return !!v; }, //获取 getter: function(v) { return v; }, //设置 setter: function(v) { return typeof v == 'string' ? document.querySelector(v) : v; } } parent: { // 默认值 value: document.body, //设置 setter: function(v) { if (!v) { return Attribute.INVALID; } return typeof v == 'string' ? document.querySelector(v) : v; } } ATTRS
value vs. valueFn parent: { // 默认值 value: document.body, //设置
setter: function(v) { if (!v) { return Attribute.INVALID; } return typeof v == 'string' ? document.querySelector(v) : v; } } parent: { // 默认值函数 valueFn: function() { return document.body; }, //设置 setter: function(v) { if (!v) { return Attribute.INVALID; } return typeof v == 'string' ? document.querySelector(v) : v; } } 防⽌止值未初始化
value vs. valueFn data: { value: { a: 1, b:
2 } } boxA.get('data').a = 2; boxB.get('data').a; // 2 data: { valueFn: function() { return { a: 1, b: 2 }; } } boxA.get('data').a = 2; boxB.get('data').a; // 1 防⽌止多实例间参数对象共同引⽤用
# CustomEvent
DOM Event Features • 绑定/移除 • 捕获/冒泡 • 阻⽌止默认⾏行为 •
阻⽌止传播 • …
on // DOM Event node.on('click', clickFn); node.on('click', clickFn, context); //
Custom Event box.on('show', showFn); box.on('show', showFn, context);
fire box.on('show', function(e) { e.visible; // true }); box.fire('show', {
visible: true });
defaultFn /** * 初始化 */ initializer: function() { //发布事件 this.publish('show',
{ defaultFn: this._defShowFn }); }, /** * 展⽰示 */ show: function() { this.fire('show'); }, /** * 默认展⽰示回调 */ _defShowFn: function() { this.box.style.display = 'block'; } box.on('show', function(e) { console.log(e); }); box.fire('show');
/** * 渲染事件 * @event render * @param {EventFacade} e
事件对象 */ this.publish('render', { defaultTargetOnly: true }); /** * 清除查询字段(query)和结果(results)事件 * @event clear * @param {EventFacade} e 事件对象 * @preventable _defClearFn */ this.publish('clear', { defaultFn: this._defClearFn }); /** * 查询事件 * @event query * @param {EventFacade} e 事件对象 * @preventable _defQueryFn */ this.publish('query', { defaultFn: this._defQueryFn }); /** * 查询结果返回事件 * @event results * @param {EventFacade} e 事件对象 e.results * @preventable _defResultsFn */ this.publish('results', { defaultFn: this._defResultsFn }); we love defaultFns! NQJBVUPDPNQMFUFCBTFKT
preventDefault /** * 初始化 */ initializer: function() { //发布事件 this.publish('show',
{ defaultFn: this._defShowFn }); }, /** * 展⽰示 */ show: function() { this.fire('show'); }, /** * 默认展⽰示回调 */ _defShowFn: function() { this.box.style.display = 'block'; } box.on('show', function(e) { e.preventDefault(); }); box.fire('show');
preventDefault box.fire(“show"); execute subscribers defaultFn prevented? end yes no
<ul> <li>one</li> <li>two</li> <li>three</li> <li>four</li> <li>five</li> <li>six</li> DOM Event bubbles
ul.delegate('click', 'li', doSomething);
Custom Event bubbles? ManagerClass instance1 instance2 instance3 instance4 instance5 instance6
manager.delegate('event', 'instance', doSomething);
bubbles //添加冒泡对象 box.addTarget(parent); box.on('show', function(e) { console.log('box'); }); parent.on('show', function(e)
{ console.log('parent'); }); box.fire('show'); /** * 初始化 */ initializer: function() { //发布事件 this.publish('show', { bubbles: true, // 默认为true defaultFn: this._defShowFn }); }, /** * 展⽰示 */ show: function() { this.fire('show'); }, /** * 默认展⽰示回调 */ _defShowFn: function() { this.box.style.display = 'block'; } વஞ
FilterPanel:select Radio:select CheckBox:select Cascade:select
stopPropagation //添加冒泡对象 box.addTarget(parent); box.on('show', function(e) { e.stopPropagation(); }); parent.on('show', function(e)
{ console.log('parent'); }); box.fire('show'); ቅᆸવஞ x
stopImmediatePropagation box.on('show', function(e) { e.stopImmediatePropagation(); }); box.on('show', function(e) { console.log('box');
}); parent.on('show', function(e) { console.log('parent'); }); box.fire('show'); ቅᆸવஞ x ቅᆸԮѬ x
defaultTargetOnly /** * 初始化 */ initializer: function() { //发布事件 this.publish('render',
{ defaultFn: this._defRenderFn, defaultTargetOnly: true }); }, /** * 渲染 */ render: function() { this.fire('render'); }, /** * 默认渲染回调 */ _defRenderFn: function() { this.box = document.createElement('div'); this.get('parent').appendChild(this.box); } //添加冒泡对象 box.addTarget(parent); box.on('render', function(e) { console.log('box'); }); parent.on('render', function(e) { console.log('parent'); }); box.render(); વஞ ቅᆸଏಪྛູવஞ
⾃自定义事件系统的实现
# AttributeObserve
/** * 展⽰示 */ show: function() { this.fire('show'); }, /**
* 默认展⽰示回调 */ _defShowFn: function() { this.box.style.display = 'block'; } box.show(); box.show(); box.show(); Y State? ીႵ؎֒భሑ
/** * 展⽰示 */ show: function() { if (!this.visible) {
this.fire('show'); this.visible = true; } }, /** * 默认展⽰示回调 */ _defShowFn: function() { this.box.style.display = 'block'; } box.show(); box.show(); box.show(); Y State ݖႿَ෫
What we expect? /** * 展⽰示 */ show: function() {
this.visible = true; }, /** * 默认展⽰示回调 */ _defShowFn: function() { this.box.style.display = 'block'; } box.show(); box.show(); box.show(); Y ሑэ߄આࠠэ߄
attrChange /** * 初始化 */ initializer: function() { // 绑定状态变化回调
this.on('afterVisibleChange', this._afterVisibleChange); }, /** * 展⽰示 */ show: function() { this.set('visible', true); }, /** * 隐藏 */ hide: function() { this.set('visible', false); }, /** * 默认展⽰示回调 */ _afterVisibleChange: function(e) { this.box.style.display = e.newVal ? 'block' : 'none'; }, box.show(); box.show(); box.show(); Y ሑэ߄આࠠэ߄
attrChange • beforeAttrChange(状态即将发⽣生变化) • afterAttrChange(状态已经发⽣生变化) • e.newVal(新值) • e.prevVal(旧值)
attrChange • beforeAttrChange(状态即将发⽣生变化) • afterAttrChange(状态已经发⽣生变化) • e.newVal(新值) • e.prevVal(旧值) 常⽤用
attrChangeData box.on('afterVisibleChange', function(e) { e.src; // UI }); // 传⼊入额外参数
box.set('visible', true, { data: { src: 'UI' } }); // 静默更新 box.set('visible', true, { silent: true }); x ҂Ԩؿ൙ࡱ
#2 继承与组合
继承与组合 • 复⽤用性 • 扩展性 • 维护性 • 低耦合 •
易通信
extend /** * 继承 * @method extend * @param {Object}
r ⼦子类 * @param {Object} s ⽗父类 * @param {Object} px 原型属性 * @param {Object} sx 静态属性 */ function extend(r, s, px, sx) { var sp = s.prototype, rp = Object.create(sp); rp.constructor = r; r.prototype = rp; r.superclass = sp; mix(rp, px); mix(r, sx); return r; } ӵჰđ҂ӵൌ২උྟ function SuperClass() { this.a = 1; } SuperClass.prototype.add = function() { console.log('add'); }; function SubClass() { this.b = 2; } SubClass.prototype.remove = function() { console.log('remove'); }; S.extend(SubClass, SuperClass, {}, {}); var sub = new SubClass(); sub instanceof SubClass; // true sub instanceof SuperClass; // true sub.add(); // add sub.remove(); // remove sub.b; // 2 sub.a; // undefined
function SuperClass() { this.a = 1; } SuperClass.prototype.add = function()
{ console.log('add'); }; function SubClass() { SubClass.superclass.constructor.apply(this, arguments); // SuperClass.apply(this, arguments); 同上 this.b = 2; } SubClass.prototype.remove = function() { console.log('remove'); }; S.extend(SubClass, SuperClass, {}, {}); sub.b; // 2 sub.a; // 1 extend טႨڳো֥ܒᄯݦඔ Ԛ߄ൌ২උྟ
extend & lifecycle function Box() { this.init.apply(this, arguments); } Box.prototype.init
= function() { this.box = document.createElement('div'); document.body.appendChild(this.box); }; function Dialog() { Dialog.superclass.constructor.apply(this, arguments); } S.extend(Dialog, Box, { init: function() { this.box.innerHTML = 'this is a dialog'; } });
extend & lifecycle function Box() { this.init.apply(this, arguments); } Box.prototype.init
= function() { this.box = document.createElement('div'); document.body.appendChild(this.box); }; function Dialog() { Dialog.superclass.constructor.apply(this, arguments); } S.extend(Dialog, Box, { init: function() { this.box.innerHTML = 'this is a dialog'; } }); FSSPSUIJTCPYJTVOEFGJOFE ڭۂ
extend & lifecycle function Box() { this.init.apply(this, arguments); } Box.prototype.init
= function() { this.box = document.createElement('div'); document.body.appendChild(this.box); }; function Dialog() { Dialog.superclass.constructor.apply(this, arguments); } S.extend(Dialog, Box, { init: function() { Dialog.superclass.init.apply(this, arguments); this.box.innerHTML = 'this is a dialog'; } });
extend & lifecycle function Box() { this.init.apply(this, arguments); } Box.prototype.init
= function() { this.box = document.createElement('div'); document.body.appendChild(this.box); }; function Dialog() { Dialog.superclass.constructor.apply(this, arguments); } S.extend(Dialog, Box, { init: function() { Dialog.superclass.init.apply(this, arguments); this.box.innerHTML = 'this is a dialog'; } }); ԩَ෫
Base.extend // 继承Base var Box = Base.extend({ /** * 初始化
*/ initializer: function() { this.box = document.createElement('div'); document.body.appendChild(this.box); }, /** * 销毁 */ destructor: function() { this.box = null; } }); // 继承Box var Dialog = Box.extend({ /** * 初始化 */ initializer: function() { this.box.innerHTML = 'this is a dialog'; }, /** * 销毁 */ destructor: function() { this.box.innerHTML = ''; } }); // 1. Box: constructor // 2. Dialog: constructor // 3. Box: initializer // 4. Dialog: initializer var dialog = new Dialog(); // 5. Dialog: destructor // 6. Box: destructor dialog.destroy(); οඨԚ߄აཧ߮
Base.extend & ATTRS // 继承Base var Box = Base.extend({ /*
... */ }, { /** * 配置参数 */ ATTRS: { parent: { /* ... */ } } }); // 继承Box var Dialog = Box.extend({ /* ... */ }, { /** * 配置参数 */ ATTRS: { type: { /* ... */ } } }); var dialog = new Dialog({ parent: '#container', type: 'alert' }); dialog.get('parent'); // div#container dialog.get('type'); // alert ᆦӻކѩҕඔᇂ
Extensions
Extensions function Mask() { this.initMask(); } Mask.ATTRS = { opacity:
{ value: 0.5 } }; Mask.prototype.initMask = function() { this.mask = document.createElement('div'); this.mask.style.opacity = this.get('opacity'); this.get('parent').appendChild(this.mask); }; // 继承Box var Dialog = Box.extend([Mask], { /* ... */ }, { /* ... */ }); var dialog = new Dialog({ parent: '#container', type: 'alert', opacity: 0.8 }); dialog.mask; // div.mask dialog.get('opacity'); // 0.8 ࢳᯒଆॶđьႿົ
KISSY.add(function(S, ACBase, ACList) { /** * ⾃自动完成组件(搜索联想) * @module autocomplete
*/ /** * ⾃自动完成组件 * @class AutoComplete * @extends AutoCompleteBase * @uses AutoCompleteList * @constructor */ var AutoComplete = ACBase.extend([ACList], {}, { name: 'AutoComplete' }); return AutoComplete; }, { requires: ['./base', './list', './index.css'] }); we love extensions! NQJBVUPDPNQMFUFJOEFYKT
KISSY.add(function (S, Pad, Radio, Mask) { /** * 单选滑动组件 *
@module slide-radio */ /** * 单选滑动组件 * @class SlideRadio * @extends Pad * @uses RadioExt * @uses MaskExt * @constructor */ var SlideRadio = Pad.extend([Radio.Ext, Mask.Ext], { /* ... */ }); return SlideRadio; }, { requires:['../pad/', '../radio/', '../mask/', './index.css'] }); we love extensions!
Extension Problems • 没有⽣生命周期 • 在形成类之后⽆无法再继续扩展
What we expect function Mask() {} Mask.ATTRS = { opacity:
{ value: 0.5 } }; S.mix(Mask.prototype, { /** * 初始化 */ initializer: function() { this.mask = document.createElement('div'); this.mask.className = 'mask'; this.mask.style.opacity = this.get('opacity'); this.get('parent').appendChild(this.mask); }, /** * 销毁 */ destructor: function() { this.get('parent').removeChild(this.mask); } }); var Dialog = Box.extend([Mask], { /* ... */ }, { /* ... */ }); // 扩充额外的扩展 Dialog.mix(OtherExt); -JGF$ZDMF ളଁᇛ௹ ᆦӻحຓঔᅚ֥ঔԉ
plugins what’s plugins?
plugins • 有依赖的宿主(PluginHost) • 插拔不影响宿主功能 • 拥有⾃自主配置 • 与宿主有交互
plugins
plugins var optimus = new Transformer(); // 初始化宿主环境 var gun
= new Gun(); // 初始化插件 optimus.gun = gun; // 插⼊入插件 optimus.gun.fire(); // 调⽤用插件⽅方法 gun.destroy(); // 销毁插件 delete optimus.gun; // 拔出插件
Base plugins function Gun() {} S.mix(Gun.prototype, { /** * 插件ID
*/ pluginId: 'Gun', /** * 插件初始化 */ pluginInitializer: function() {}, /** * 插件销毁 */ pluginDestructor: function() {}, /** * 开⽕火 */ fire: function() { } }); var optimus = new Transformer(); // 初始化宿主环境 optimus.plug(Gun); // 初始化并插⼊入插件 optimus.getPlugin('Gun').fire(); // 调⽤用插件⽅方法 optimus.unplug('Gun'); // 销毁插件
Base plugin problems • 有依赖的宿主(PluginHost) • 插拔不影响宿主功能 • 拥有⾃自主配置(过于简单不⽀支持传参) •
与宿主有交互(没有⽅方法与宿主交互)
What we expect var Gun = Plugin.extend({ pid: 'Gun', /**
* 初始化 */ initializer: function() { console.log(this.get('host')); console.log(this.get('bullets')); }, /** * 初始化 */ destructor: function() { /* ... */ } }, { ATTRS: { bullets: { value: 1000 } } }); var optimus = new Transformer(); optimus.plug(Gun, { bullets: 2000 }); // optimus // 2000
Extension vs. Plugin • 类级别 • 修改原型 • 必要的功能 •
实例级别 • 不修改原型 • ⾮非必要的功能
Base • LifeCycle • CustomEvent • Attribute • Extension •
Plugin
Base • LifeCycle • CustomEvent • Attribute • Extension •
Plugin "MM'SFF
None
SuperBase what’s SB?
SuperBase • Fix Extension Problems • After Event • AOP
Fix Extension Problems • 增加扩展⽣生命周期 • ⽀支持额外扩展的扩充
var Calendar = Pad.extend([Mask.Ext], { /** * 选中⽇日期节点 */ select:
function(item) { this.fire('select', { item: item }); }, /** * 默认选中⽇日期节点 */ _defSelectFn: function(e) { this._selectedItem = e.item; this._selectedItem.addClass('selected'); } }); After Event var calendar = new Calendar(); calendar.on('select', function(e) { console.log(this._selectedItem); // null }); calendar.select(item); ೂޅᄝଏಪྛູᆭުԩઆࠠĤ
var Calendar = Pad.extend([Mask.Ext], { /** * 选中⽇日期节点 */ select:
function(item) { this.fire('select', { item: item }); }, /** * 默认选中⽇日期节点 */ _defSelectFn: function(e) { this._selectedItem = e.item; this._selectedItem.addClass('selected'); } }); What we expect োරႿBUUS$IBOHF ᄝଏಪྛູᆭުԩઆࠠ var calendar = new Calendar(); calendar.after('select', function(e) { console.log(this._selectedItem); // item }); calendar.select(item);
instance event _defEventFn instance.on(event,handler) instance.after(event,handler) after
AOP what’s AOP? ⾯面向切⾯面编程
AOP function Mask() {} Mask.prototype.renderMask = function() { this.mask =
document.createElement('div'); this.get('parent').insertBefore(this.box, this.mask); }; var Box = Base.extend({ render: function() { this.box = document.createElement('div'); this.get('parent').appendChild(this.box); } }); var Dialog = Box.extend([Mask], {}); ೂޅᄝ҂ྩڿჰٚم֥భิ༯ ࡼSFOEFS.BTL٢֞SFOEFSުᆳྛĤ
function Mask() { this.doAfter(this.renderMask, this, 'render', this); } Mask.prototype.renderMask =
function() { this.mask = document.createElement('div'); this.get('parent').insertBefore(this.box, this.mask); }; var Box = Base.extend({ render: function() { this.box = document.createElement('div'); this.get('parent').appendChild(this.box); } }); var Dialog = Box.extend([Mask], {}); AOP SFOEFS.BTLࡼᄝSFOEFSުᆳྛ
more AOP • ⽆无缝侵⼊入⽅方法(before,after) • 阻⽌止原⽅方法的执⾏行(prevent) • 阻⽌止AOP⽅方法的传播(halt) • 修改传参(before,AlterArgs)
• 修改返回值(after,AlterReturn) • …
SuperBase • LifeCycle • CustomEvent+ • Attribute • Extension+ •
Plugin • AOP
SuperBase • LifeCycle • CustomEvent+ • Attribute • Extension+ •
Plugin • AOP "MM'SFF
None
# Q&A