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
20260914 AIエージェント時代のPlatform Engineering LLM基盤とプロダクトの責務境界線
kanfab1
6
1.8k
How I Stole PSI from Android Studio - DroidKaigi2026
worker8
0
120
LLMは4年分のCompose移行を再現できるのか?実プロダクト279件のXMLで探る自動化の境界線
makun
0
870
JPUG勉強会 OSSデータベースの内部構造を理解しよう(第2回)
oga5
0
220
モバイル交通系ICへのチャージ実例から考える、クロスプラットフォーム開発におけるiOS実機テスト設計とCI運用
yusuga
1
460
Go のフラットな パッケージに 「ファイル単位の private」を 〜Linter “declscope” を作った話〜
mpyw
0
290
大喜利で理解するLLM as a Judge / Understanding LLM-as-a-Judge through Ogiri
rockname
0
100
新卒PdEのリアル
ryu1013
1
500
WebMCP Challenge に星空観察アプリで参加した話
okajun35
0
160
選挙速報を多くのユーザーへ 届ける Live Activities 設計
hamayokokuririn
0
140
マイコン向けの軽量Ruby「PicoRuby」で各種デバイスを制御するネイティブアプリの実現手法
bash0c7
0
390
Streamlitで実現する自然言語データアプリ開発
ayumu_yamaguchi
0
270
Featured
See All Featured
ラッコキーワード サービス紹介資料
rakko
1
4.9M
The Anti-SEO Checklist Checklist. Pubcon Cyber Week
ryanjones
0
240
The MySQL Ecosystem @ GitHub 2015
samlambert
251
13k
Put a Button on it: Removing Barriers to Going Fast.
kastner
60
4.6k
Thoughts on Productivity
jonyablonski
76
5.4k
Noah Learner - AI + Me: how we built a GSC Bulk Export data pipeline
techseoconnect
PRO
0
430
The Pragmatic Product Professional
lauravandoore
37
7.4k
The Invisible Side of Design
smashingmag
301
52k
Leadership Guide Workshop - DevTernity 2021
reverentgeek
1
370
技術選定の審美眼(2025年版) / Understanding the Spiral of Technologies 2025 edition
twada
PRO
120
120k
Designing for Timeless Needs
cassininazir
1
480
Hiding What from Whom? A Critical Review of the History of Programming languages for Music
tomoyanonymous
3
1.2k
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