<Page >

  <p>使用 `Roof.Node` 非常简单。先使用 `Roof.Node` 创建用户自己的数据类型(以下都称为 **type**)，再进行实例化。`Roof.Node` 不可以直接实例化。</p>

  <Code type='javascript'>{`
var Roof = require('roof')
var User = Roof.Node.createClass()
var user = new User({name:roof, age:0, like:{sport:'basketball'})
	`}</Code>

    <h1>API</h1>

    <Api name='get'>


    <p>简单读取数据</p>

    <Code type='javascript'>{`
user.get('name')
		`}</Code>

    <p>深度读取</p>

    <Code type='javascript'>{`
user.get('like.sport')
		`}</Code>

    </Api>

    <Api name='set'>


    <p>简单写数据</p>

    <Code type='javascript'>{`
user.set("age", 1)
user.get("age") // 1
		`}</Code>

    <p>深度写入</p>

    <Code type='javascript'>{`
user.set("tools",{
    "node": "This node is not that node",
    "bus" : "This bus is not that bus"
})

user.get("tools.node") //得到 This node is not that node

user.set("tools.bus", "Bus is event bus")
user.get("tools.bus") //得到 Bus is event bus
		`}</Code>

    <p>`set` 方法还支持更友好地批量修改:</p>

    <Code type='javascript'>{`
user.set({name:"ava",age:1})
user.set({
    "like.movie" : "Whisper",
    "like.song" : "Tresspassing"
})

user.get("like") //得到{movie:"Whisper",song:"Tresspassing"}
		`}</Code>

    <Alert type='danger'>
    要注意的是，如果 set 的数据是对象，那么保存的是它的引用。建议在set 完之后就不要在操作原来的对象，以免引起数据不一致。
    </Alert>

    <Code type='javascript'>{`
var norah = {name:"norah"}
user.set("child",norah)
console.log( user.getRef("child") === norah ) //true
		`}</Code>

    </Api>


    <Api name='destroy'>
    <p>使用 `destroy` 方法即可销毁对象, 所有会修改到数据的 api 都被冻结了，调用时会抛出警告。</p>
    </Api>

    <Api name='is'>
    <p>判断实例当前的状态，详见 **高级 API** 一节。</p>
    </Api>

    <Api name='on'>
    <p>监听实例上的事件，详见 **监听数据事件** 一节。</p>
    </Api>

    <Api name='fire'>
    <p>在实例上触发事件，监听实例上的事件，详见 **监听数据事件** 一节。</p>
    </Api>

    <h1>自定义 API</h1>

    <h2>普通 API</h2>

    <p>用户在创建自己的 type 时，可以定义当前 type 特有的 API。</p>

    <Code type='javascript'>{`
var User = Node.createClass({
    setFullName : function( fullName ){
        var tmp = fullName.split(' ')
        this.set("name", tmp[0])
        this.set("family", tmp[1])
    },
    getFullName : function(){
        return this.get("name") +" "+this.get("family")
    }
})

var user = new User({name:"Ian",family:"William"})

console.log(user.getFullName()) //"Ian William"

user.setFullName("Jhon Smith")
user.get('name')       //"Jhon"
user.get('family')     //"Smith"
		`}</Code>

    <h2>高级 API (以下统称为 action)</h2>
    <p>定义 API 时，可以同时给它的状态取名字，配合 `is` 方法来判断。首先我们来定义一个 API doSometing，给它 “没有执行过” 的状态取名为 “doSomething.no”。给 “执行过” 的状态取名为 "doSomething.yes"。定义过状态的的 API 我们统称为 **action**, 和普通 API 区别开。
    </p>

    <Code type='javasript'>{`
var User = Roof.Node.createClass({
	doSomething : [function(){
		//do something
	},'doSomething.no','doSomething.yes']
})
		`}</Code>

    <p>判断它的状态</p>
    <Code type='javasript'>{`
var user = new User

user.is('doSometing.no')  //true
user.is('doSometing.yes') //false

user.doSomething()
user.is('doSometing.no')  //false
user.is('doSometing.yes') //true
		`}</Code>

    <p>如果 action 的操作是异步的，那么可以定义三个状态:</p>

    <Code type='javasript'>{`
var User = Roof.Node.createClass({
	doSomething : [function(){
		//do something async
		return new Promise(function(resolve, reject){
			setTimeout(function(){
				resolve()
			},1000)
		})
	},'doSomething.initial','doSomething.processing','doSomething.end']
})

var user = new User

user.is('doSomething.initial')      //true
user.is('doSomething.processing')   //true
user.is('doSomething.end')          //false

var promise = user.doSomething()

user.is('doSomething.prcessing')    //true
user.is('doSomething.end')          //false

promise.then(function(){
	user.is('doSomething.end')      //true
})
		`}</Code>

    <p>`is` 可以同时判断多个状态:</p>

    <Code type='javascript'>{`
user.is('a', 'b')     //表示必须有 a 状态，也必须有 b 状态
user.is(['a','b'])    //表示有 a 状态，或者有 b 状态
user.is(a,['b','c'])  //表示有 a 状态，并且有 b 或者 c 状态

//is 支持无限多个参数
		`}</Code>

    <h2>监听数据事件</h2>

    <p>当执行 action 时，Node 会将状态的变化作为事件抛出。注意，一定要在执行动作前调用 `on` 来监听。</p>

    <Code type='javascript'>{`
var User = Roof.Node.createClass({
	doSomething : [function(){
		//do something
	},'doSomething.no','doSomething.yes']
})

var user = new User

user.on('doSomething.yes', function(currentState, lastState){
	currentState === 'doSomething.yes'   //true
	lastState === 'doSomething.no'   //true
})

user.doSomething()
`}</Code>

    <p>我们也可以使用 `fire` 方法手动触发事件，可以传递任意多个参数。注意，尽量不要手动触发 action 会触发的事件。</p>

    <Code type='javascript'>{`
user.on('manualEvent', function( someArg ){
	console.log('manualEvent fired', someArg )
})

user.fire('manualEvent', 'icecream')
		`}</Code>

    <p>除了监听具体的状态变化，我们还可以直接监听 `change` 事件，这个事件在任何状态变化时都会触发:</p>

    <Code type='javascript'>{`
var User = Roof.Node.createClass({
	doSomething : [function(){
		//do something
	},'doSomething.no','doSomething.yes']
})

var user = new User

user.on('change', function(currentState, lastState){
	console.log(currentState) //doSomething.yes
	console.log(lastState)    //doSomething.no
})

user.doSomething()
		`}</Code>

    </Page>





