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
Sponsored
·
Ship Features Fearlessly
Turn features on and off without deploys. Used by thousands of Ruby developers.
→
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
210
React & Component
ningzbruc
0
63
阿里旅行去啊H5首页总结&Promise
ningzbruc
0
280
Hammer.js
ningzbruc
1
360
淘宝旅行门票iPad版开发
ningzbruc
0
160
Travel on KISSY mini
ningzbruc
0
210
Events
ningzbruc
2
130
Why YUI3
ningzbruc
0
190
Other Decks in Programming
See All in Programming
Apple Intelligenceとオンデバイス時代の到来
yahir0
0
180
AI Augmentation Techniques with Liberty
ivargrimstad
0
220
SODA - FACT BOOK(JP)
sodainc
1
40k
Web Framework Benchmark Battle 2026, Any%
a_matsuda
3
3.1k
Web3Dライブラリを作ってVue Custom Rendererの仕組みを理解しよう / lets learn vue custom renderer by making 3d library
drumath2237
1
110
Compiling a real-world CLI tool to native with Static Hermes
tmikov2023
0
140
Performance Optimization With LLMs
xleitix
0
230
あなたの await、OS まで届いてる? strace で覗く JavaScript の非同期
hasutosasaki
1
1.7k
SODA - FACT BOOK(EN)
sodainc
1
200
No More NoSuchMethodError
exoego
1
120
Python Lambdaにおけるテストしやすい設計とAI支援の活用 / Designing Testable Python Lambda Functions with AI
kitano_yuichi
1
270
SFCで実現する病院・医療システムの動的組み立て式UI
koukimiura
1
150
Featured
See All Featured
Everyday Curiosity
cassininazir
0
380
How to Create Impact in a Changing Tech Landscape [PerfNow 2023]
tammyeverts
56
3.5k
Paper Plane (Part 1)
katiecoart
PRO
2
12k
XXLCSS - How to scale CSS and keep your sanity
sugarenia
250
1.3M
Bootstrapping a Software Product
garrettdimon
PRO
306
120k
The Art of Programming - Codeland 2020
erikaheidi
57
14k
GraphQLの誤解/rethinking-graphql
sonatard
75
12k
Building Experiences: Design Systems, User Experience, and Full Site Editing
marktimemedia
1
650
Efficient Content Optimization with Google Search Console & Apps Script
katarinadahlin
PRO
1
950
A Soul's Torment
seathinner
8
3.9k
Design and Strategy: How to Deal with People Who Don’t "Get" Design
morganepeng
133
20k
Google's AI Overviews - The New Search
badams
0
1.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