Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
KISSY.Base - all about that Base
Search
ningzbruc
August 06, 2015
Programming
140
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
68
去啊无线前端的一天
ningzbruc
1
200
React & Component
ningzbruc
0
47
阿里旅行去啊H5首页总结&Promise
ningzbruc
0
270
Hammer.js
ningzbruc
1
340
淘宝旅行门票iPad版开发
ningzbruc
0
140
Travel on KISSY mini
ningzbruc
0
210
Events
ningzbruc
2
130
Why YUI3
ningzbruc
0
190
Other Decks in Programming
See All in Programming
自分的「カンファレンスの楽しみ方」
syumai
0
200
iOSDC Japan 2026 - Swiftで作って学ぼう!データベース自作入門
kaseken
2
160
AIは賢い。でも実行環境は? CLIおじさんがAI時代に伝えたいこと ~ CLIおじさんがAI時代に伝えたいこと ~
curekoshimizu
1
240
【DroidKaigi 2026】「アクセシビリティを利用するとき、 アクセシビリティもまたこちらを利用している」 〜マルウェアによる攻撃と防衛について〜
halunoyo
0
460
Building an Out-of-Order CPU
latte72
1
770
App Intentsのビルドプロセスを支える技術
kntkymt
0
360
The Good Stuff, Not the Slop: Engineering High-Quality Android Apps with Modern AI Tooling
danybony
1
250
技術的負債の返済は、AI時代の複利で効く投資 — 経営としての意思決定とその遂行
curekoshimizu
0
1.2k
スマートフォンでモールス信号を送受信する 〜スマートフォンのLEDとカメラで作る光通信の設計と実装〜
atsuki_seo
0
110
マイコン向けの軽量Ruby「PicoRuby」で各種デバイスを制御するネイティブアプリの実現手法
bash0c7
0
390
技術的負債を組織課題として解く-増えすぎたマイクロサービスとの戦い-
reimaru
1
1.7k
[DroidKaigi 2026] Bring your own phones to Gradle Managed Devices
f2lk
0
120
Featured
See All Featured
The Spectacular Lies of Maps
axbom
PRO
1
990
Lessons Learnt from Crawling 1000+ Websites
charlesmeaden
PRO
1
1.6k
Winning Ecommerce Organic Search in an AI Era - #searchnstuff2025
aleyda
1
2.1k
Abbi's Birthday
coloredviolet
4
10k
個人開発の失敗を避けるイケてる考え方 / tips for indie hackers
panda_program
123
22k
The Straight Up "How To Draw Better" Workshop
denniskardys
239
140k
Sharpening the Axe: The Primacy of Toolmaking
bcantrill
46
3k
svc-hook: hooking system calls on ARM64 by binary rewriting
retrage
2
570
Marketing Yourself as an Engineer | Alaka | Gurzu
gurzu
0
300
Tips & Tricks on How to Get Your First Job In Tech
honzajavorek
1
740
We Are The Robots
honzajavorek
0
370
Designing Experiences People Love
moore
143
24k
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