jquery-statebusking v0.0.2
jquery-statebusking
πΈBackbone alternative using jquery-statebus
jquery-statebuskingμ jquery-statebusλ₯Ό λ°±λ³Έ(backbone)μ²λΌ λ§λλλ€. μ€ν μ΄, λ·°λ₯Ό μ μν©λλ€. μ μλ μ€ν μ΄, λ·°λ λ°λ³΅ν΄μ μ¬μ¬μ© ν μ μμ΅λλ€.
Why?
jquery-statebusλ λ·°μ μνλ₯Ό λΆλ¦¬νλ μμ£Ό κ°λ¨ν ν¨ν΄μ μ 곡νμ§λ§, λ°λ³΅λλ μν, λ·°λ₯Ό μ²λ¦¬νκΈ° μν νΈμλ μ 곡νμ§ μμ΅λλ€. jquery-statebuskingλ μ΄ μ μ 보μν©λλ€.
vs Backbone
- No underscore - statebuskingμ underscoreμ λν μμ‘΄μ±μ΄ μμ΅λλ€. (μ λ lodashλ₯Ό λ μ’μν©λλ€.)
- View state - λ°±λ³Έμ λ·°λ μνκ΄λ¦¬λ₯Ό λͺ¨λΈμ μ μ μΌλ‘ μμ‘΄νμ§λ§ jquery-statebuskingμ λ΄λΆμνλ₯Ό κ°μ§ μ μμ΅λλ€.
Install
<script src="https://code.jquery.com/jquery.min.js"></script>
<script src="https://unpkg.com/jquery-statebus"></script>
<script src="https://unpkg.com/jquery-statebusking"></script>
Exmaple
<div id="counter">
<span class="value"></span>
<button class="increment"> + </button>
<button class="decrement"> - </button>
</div>
var Counter = $.statebus.store('Counter', {
state: {
value: 1
},
action: {
increment: function() {
return {value: this.state.value + 1}
},
decrement: function() {
return {value: this.state.value - 1}
}
}
})
var CounterView = $.statebus.view('CounterView', {
events: {
'click button.increment': 'onIncrementClick',
'click button.decrement': 'onDecrementClick'
},
init: function(options) {
var counter = this.counter = options.counter
this.$value = this.$el.find('span.value')
this.listenTo(counter, 'all', this.render, true)
},
render: function() {
var value = this.counter.state.value
this.$value.text(value)
},
onIncrementClick: function() {
this.counter.action.increment()
},
onDecrementClick: function(){
this.counter.action.decrement()
}
})
new CounterView({ el: '#counter', counter: new Counter('app/counter') })
Store
μ€ν μ΄λ λ·°μ λΆλ¦¬λμ μ± μνμ λ‘μ§μ κ΄λ¦¬ν©λλ€. λ°±λ³Έμ μ½λ μ , λͺ¨λΈκ³Ό λΉμ·ν©λλ€.
Definition
μ€ν μ΄λ₯Ό μ μν©λλ€.
var Counter = $.statebus.store('Counter', {
state: {
value: 1
},
action:{
increment: function() {
return {value: this.state.value + 1}
},
decrement: function() {
return {value: this.state.value - 1}
}
},
})
μ‘μ λ©μλμ λ°νκ²°κ³Όκ° κΈ°μ‘΄ μνμ λ³ν©λμ΄ μλ‘μ΄ μνλ₯Ό λ§λλλ€.
Create
μ μν μ€ν μ΄λ₯Ό μμ±νλ λ°©λ²μ 2κ°μ§μ λλ€.
var counter = new Counter('app/counter')
// λλ
var counter = $.statebus.createStore('Counter', 'app/counter')
μ€ν μ΄ μμ±μ, μ΄λ¦
μ΄ νμν©λλ€. μ΄λ¦μ΄ νμν μ΄μ λ μλ Name Systemμμ μ€λͺ
ν©λλ€.
Event
store.on()
λ©μλλ‘ μ‘μ
μ΄λ²€νΈλ₯Ό μ²μ·¨ν μ μμ΅λλ€.
counter.on('increment', function (){
console.log('incremented!!')
})
counter.action.increment()
// => incremented!
"all" μ΄λ²€νΈλ‘ λͺ¨λ μ‘μ μ΄λ²€νΈλ₯Ό μ²μ·¨ν μ μμ΅λλ€.
counter.on('all', function (){ ... })
Method
state, actionμΈ λ€λ₯Έ λ©μλλ₯Ό μ μν΄μ μ¬μ©ν μ μμ΅λλ€.
$.statebus.store('Counter', {
...
format: function(){
return 'μ΄ ' + this.state.value + 'ν'
}
})
...
var formatted = counter.format()
console.log(formatted)
// => μ΄ 1ν
Mixin
λ―Ήμ€μΈμ μ¬λ¬ μ€ν μ΄ μ μλ₯Ό νλλ‘ ν©μΉ©λλ€. λ―Ήμ€μΈμ νμ©νλ©΄ λ°λ³΅μ μΈ μ€ν μ΄ μ μλ₯Ό μ€μΌ μ μμ΅λλ€.
var A = $.statebus.store('A', {
state: {
valueA: ''
},
action: {
setA: function(a) {
return {valueA: a}
},
}
})
// 2λ²μ§Έ μΈμλ‘ λ―Ήμ€μΈ λμμ μ§μ ν©λλ€.
var B = $.statebus.store('B', A, {
state: {
valueB: ''
},
action: {
setB: function(b) {
return {valueA: b}
},
},
print: function() {
console.log(this.state.valueA + '-' + this.state.valueB)
}
})
var b = new B('app/b')
b.action.setA('foo')
b.action.setB('BAR')
b.print()
// => foo-BAR
λ°°μ΄λ‘ μ¬λ¬ μ€ν μ΄ μ μλ₯Ό λ―Ήμ€μΈ ν μ μμ΅λλ€.
$.statebus.store('A', [B, C, D], { ... })
// λλ
$.statebus.store('A', ['B', 'C', 'D'], { ... })
Initialize
store.init()
μ μ μνλ©΄ μμ±μ μ΄κΈ°ν μμ
μ ν μ μμ΅λλ€.
var Store = $.statebus.store('Store', {
state: {
value: null
},
init: function(options) {
this.state.value = options.value
}
})
// μ€ν μ΄ μμ±μ λλ²μ§Έ μΈμλ‘ initν¨μμ 맀κ°λ³μλ₯Ό λκ²¨μ€ μ μμ΅λλ€.
var store = new Store('app/store', { value: true })
μνλ₯Ό λμ μΌλ‘ μ μν λ μ μ©ν©λλ€.
Name System
statebuskingμ jqueryλ₯Ό μ¬μ©ν λ κ±°μ μ½λλ₯Ό κ°μ νκΈ° μν΄ λ§λ€μ΄μ‘μ΅λλ€. μ΄λ¬ν νκ²½μμλ μ λλ‘ λ λͺ¨λμμ€ν
μ κΈ°λνκΈ° μ΄λ €μΈ λκ° λ§μ΅λλ€.
μ€ν μ΄ μ μνκ±°λ μμ±ν λ μ΄λ¦(name)
μ μ§μ νμ¬ μμ‘΄μ±μ ν΄κ²°νλ©΄ λͺ¨λμμ€ν
μ΄ μμ λ μ μ©ν©λλ€.
$.statebus.store('Counter', { ... }) // μ€ν μ΄ μ μ
$.statebus.store('A', ['B', 'C'], { ... }) // μ€ν μ΄ λ―Ήμ€μΈ
$.statebus.createStore('Counter', 'app/counter') // μ€ν μ΄ μμ±
$.statebus.remove('app/counter') // μ€ν μ΄ μ κ±°
Remove
μ€ν μ΄λ₯Ό μ κ±°ν©λλ€.
new Model('app/model')
$.statebus.remove('app/model')
statebuskingμ μ€ν μ΄(store)λ μ μ μ λλ€.
λ°±λ³Έμ λͺ¨λΈμ²λΌ λμ μΌλ‘ μ κ±°λ₯Ό ν μλ μμ§λ§ μΆμ²νμ§ μμ΅λλ€. λλλ‘ μ€ν μ΄λ₯Ό μ§μ μ κ±°νλ λμ , λμ μΈ μνλ₯Ό μ μνκ³ μ‘μ λ©μλλ‘ μν κ°μ μ κ±°νμΈμ.
View
λ·°λ μνλ₯Ό λ΄λΉνλ μ€ν μ΄μ λΆλ¦¬λμ΄ DOM λ³νλ₯Ό κ΄λ¦¬ν©λλ€.
Definition
λ·°λ₯Ό μ μν©λλ€.
var CounterView = $.statebus.view('CounterView', {
init: function() { ... },
...
})
μ€ν μ΄μ²λΌ view.init()
μ μ μνλ©΄ μμ±μ μ΄κΈ°ν μμ
μ ν μ μμ΅λλ€.
Create
μ μν λ·°λ₯Ό μμ±νλ λ°©λ² μμ 2κ°μ§μ λλ€. λ·° μμ±μ μ΅μ κ°μ²΄λ₯Ό μΈμλ‘ λκ²¨μ€ μ μμ΅λλ€.
var view = new CounterView({el: '#counter'})
// λλ
var view = $.statebus.createView('CounterView', {el: '#counter'})
λ·°λ jqueryλ‘ λνλ DOM μ리먼νΈμΈ view.$el
μ κ°μ§λλ€. μ΅μ
μ el
μμ±μΌλ‘ DOM μ리먼νΈλ₯Ό μ νν μ μμ΅λλ€.
console.log(view.$el.get(0))
// => <div id="counter">...</div>
미리 μ μΈλ¨κ³μμ μ§μ ν μλ μμ΅λλ€.
$.statebus.view('CounterView', {
el: '#counter',
...
})
λ§μ½ μ§μ ν el
μ΄ μλ€λ©΄ tagName
μ μ리먼νΈλ₯Ό λ§λλλ€. μ΄ λ μ§μ λ¬Έμμ μ½μ
ν΄μΌ ν©λλ€.
var view = new CounterView({tagName: 'div'})
view.$el.appendTo('body')
tagName
μ κΈ°λ³Έκ°μ "div"μ
λλ€.
Mixin
λ·° μμ μ€ν μ΄μ²λΌ λ―Ήμ€μΈμ΄ κ°λ₯ν©λλ€.
$.statebus.view('A', ['B', 'C'], { ... })
Event delegate
events
μμ±μΌλ‘ view.$elμμ λ°μνλ μ΄λ²€νΈμ νΈλ€λ¬ λ©μλλ₯Ό 맀νν μ μμ΅λλ€.
$.statebus.view('View', {
events: {
// view.$elμμ click μ΄λ²€νΈκ° λ°μμ, onClick λ©μλλ₯Ό μ€νν©λλ€.
'click': 'onClick',
// νΉμ μμμμμμ λ°μνλ μ΄λ²€νΈλ₯Ό 맀νν μλ μμ΅λλ€.
'click .child': 'onClick'
},
// jquery event κ°μ²΄λ₯Ό 맀κ°λ³μλ‘ λ°μ΅λλ€.
onClick: function(event) { ... }
})
μ νκΈ°λ²μ μ¬μ©ν΄ λ©μλλ₯Ό 맀νν μ μμ΅λλ€. μ΄λ²€νΈ λ°μμ λ°λ‘ μ‘μ λ©μλλ₯Ό μ€νν λ μ μ©ν©λλ€.
$.statebus.view('CounterView', {
events: {
'click': 'counter.action.increment'
},
init: function(options) {
this.counter = options.counter
}
})
νΈλ€λ¬λ©μλ thisλ₯Ό λ·° κ°μ²΄λ‘ μλλ°μΈλ©ν©λλ€. λ°λΌμ λ©μλ thisκ° κ³ μ λμ§ μμ κ²½μ°, μλνμ§ μμ λμμ΄ λ°μν μ μμ΅λλ€. λ€νν μ€ν μ΄ μ‘μ λ©μλλ€μ this λ°μΈλ©μ΄ 미리 λμ΄ μμ΄ μμ ν©λλ€.
Stateful
statebuskingμ λ°±λ³Έκ³Ό λ¬λ¦¬, λ·° μν
λ κ°λ
μ΄ μ‘΄μ¬ν©λλ€.
$.statebus.view('CounterView', {
state: {
value: 1
},
action: {
increment: function() {
return {value: this.state.value + 1}
},
},
events: {
'click button.increment': 'action.increment'
}
})
μ΄κ²μ μ± μν
μ λ·° μν
μ κ²½κ³λ₯Ό λͺ
ννκ² ν΄μ μνκ΄λ¦¬μ λμμ μ€λλ€.
Options
λ·°λ₯Ό μμ±μ, μλ μ΅μ κ°μ²΄ μμ±μ μ°Έμ‘°ν©λλ€.
el
- λ·° μλ¦¬λ¨ΌνΈ μμ(view.$el)λ₯Ό μ νν©λλ€.events
- DOM μλ¦¬λ¨ΌνΈ μ΄λ²€νΈμ νΈλ€λ¬ λ©μλλ₯Ό 맀νν©λλ€.attrs
- DOM μ΄νΈλ¦¬λ·°νΈλ₯Ό μ€μ ν©λλ€.tagName
-el
μ΄ μμ κ²½μ°,tagName
μμ±μ μλ¦¬λ¨ΌνΈ λ§λλλ€. κΈ°λ³Έκ°μ "div"μ λλ€.
μ΅μ μ μμ±λ€μ μ μλ¨κ³μμ 미리 μ μΈν μ μμ΅λλ€.
view.listenTo(store, actionName, listener ,immediately)
μ€ν μ΄μ μ‘μ μ΄λ²€νΈλ₯Ό ꡬλ ν©λλ€.
store
Store|string - λμ μ€ν μ΄.μ΄λ¦
(string)μΌλ‘ μ€ν μ΄λ₯Ό μ§μ ν μ μμ΅λλ€.actionName
string|string[] - ꡬλ ν μ‘μ μ΄λ²€νΈμ λλ€.listener
(this:View, store, context) => void - μ‘μ μ΄ λ°μνμ λ μ€νλ 리μ€λ ν¨μμ λλ€.immediately
boolean - μ¦μ μ€νμ¬λΆμ λλ€. κΈ°λ³Έκ°μ falseμ λλ€.
...,
init: function(){
this.listenTo(counter, 'increment decrement', this.render, true)
// λλ
this.listenTo('app/counter', 'increment decrement', this.render, true)
},
...
view.listenTo()
λ ꡬλ
μ μ·¨μν μ μλ ν¨μλ₯Ό λ°νν©λλ€. μνλ μμ μ μ΄λ²€νΈ ꡬλ
μ μ·¨μν μ μμ΅λλ€.
...,
init: function() {
this.unsubscribe = this.listenTo('app/counter', 'increment decrement', this.render)
},
onClick: function() {
// μ‘μ
μ΄λ²€νΈ ꡬλ
μ μ·¨μν©λλ€.
this.unsubscribe()
},
...
view.on(actionName, listener ,immediately)
λ·°μ μ‘μ μ΄λ²€νΈλ₯Ό ꡬλ ν©λλ€.
actionName
string|string[] - ꡬλ ν μ‘μ μ΄λ²€νΈμ λλ€.listener
(view, context) => void - μ‘μ μ΄ λ°μνμ λ μ€νλ 리μ€λ ν¨μμ λλ€.immediately
boolean - μ¦μ μ€νμ¬λΆμ λλ€. κΈ°λ³Έκ°μ falseμ λλ€.
view.listenTo()
μ λ§μ°¬κ°μ§λ‘ ꡬλ
μ μ·¨μν μ μλ ν¨μλ₯Ό λ°νλ°μ΅λλ€
...,
action: {
increment: function() { ... },
},
init: function(){
this.unsubscribe = this.on('increment decrement', $.proxy(this.render, this))
},
...
λ¨ view.listenTo()
μ λ¬λ¦¬ view.on()
μ λ·° μΈλΆμμ μ¬μ©νλ κ²½μ°λ₯Ό κ³ λ €ν΄μ thisλ₯Ό μλλ°μΈλνμ§ μμ΅λλ€. $.proxy, λλ ES5 bind ν¨μλ‘ thisλ₯Ό λ°μΈλνμΈμ.
view.$(selector)
λ·° μ리먼νΈμ μμμμλ₯Ό μ νν©λλ€. view.$el.find()
μ μΆμ½ ν¨μμ
λλ€.
view.getState(store, key ,defaults)
μ€ν μ΄ μνλ₯Ό μ»μ΅λλ€.
store
Store|string - λμ μ€ν μ΄.μ΄λ¦
(string)μΌλ‘ μ€ν μ΄λ₯Ό μ§μ ν μ μμ΅λλ€.key
string - μμ±λͺ . μ νκΈ°λ²μ μ¬μ©ν΄μ κΉμ(nested) κ³³μ μμΉν κ°μ κ°μ Έμ¬ μ μμ΅λλ€.defaults
undefined - κ°μ΄ μ‘΄μ¬νμ§ μμ λ λ°νν κΈ°λ³Έκ°.
...,
init: function() {
this.articleTitle = this.getState('app/articles', 'articles.0.title')
}
view.getPrevState(store, key ,default)
μ€ν μ΄μ λ³κ²½ μ§μ μ μνλ₯Ό μ»μ΅λλ€.
view.dispatch(actionName, ...args)
view.listenTo()
λ‘ κ΅¬λ
μ€μΈ μ€ν μ΄μ μ§μ ν μ‘μ
μ μΌκ΄ μ€νν©λλ€.
$.statebus.store('Post', {
...
action: {
onPostWrite: function(post) {
return {post: post}
}
}
})
$.statebus.view('PostView', {
...,
init: function() {
this.listenTo('app/post', 'all', this.render)
}
onSubmit: function(){
var post = this.$textarea.val()
this.dispatch('onPostWrite', post)
},
...
})
μ€ν μ΄μ μ‘μ μ 리μ‘ν°λΈν ννλ‘ λμμΈ νμ λ μ μ©ν©λλ€.
view.dispatchAll(actionName, ...args)
μμ±λ λͺ¨λ μ€ν μ΄μ μ§μ ν μ‘μ μ μΌκ΄ μ€νν©λλ€.
view.remove()
λ·° μ리먼νΈλ₯Ό μ κ±°ν©λλ€. μ€ν μ΄μ λν λͺ¨λ ꡬλ μμ μ·¨μν©λλ€.
λ°±λ³Έκ³Ό λ¬λ¦¬ μμ (remove)μ΄λ²€νΈλ₯Ό μ 곡νμ§ μμ΅λλ€.
statebuskingμ λ·°μ κ±°λ₯Ό λΆλͺ¨μμκ° κ²°μ νλ€λ μμΉμ λ―Ώμ΅λλ€. λ·°μ λ·°μ μμ μ΄λ²€νΈκ° νμνλ€λ©΄ λΆλͺ¨ λ·°μ μ‘μ λ©μλμ μ‘μ μ΄λ²€νΈλ₯Ό μ¬μ©ν©λλ€.
Example Codes
License
MIT