riotjs 2.2.4

riotjs

riotjs一款小型的10000star mvp框架。目前進化至3.x版本了。讀者注意,本篇文章介紹的是2.2.4哦。爲啥介紹這款啊,是由於那個啥,preact面向現代瀏覽器,對我來講不咋好使。css

riotjs從出生到如今總共經歷了3個大版本,基本上每一個都不同,1.x最爲簡陋,能夠視之就一個簡單的mvc框架哦,模板引擎也是簡單的不要不要的,2.x版本完善了各項功能,而且強化了controller的做用,使之成爲一個真正的MVP框架。3.x版本使用了大量es6,es5新增方法進行重構,對svg支持,模板引擎,事件系統,內存使用等進行了必定程度的優化。(實際從2.3開始就往現代瀏覽器上靠了)html

爲什麼選用

因爲riotjs小,容易和其餘框架混合使用react

特色

小,但經不起強渲染es6

支持ie8嗎

riotjs 2.2.4是最後一個支持ie8的版本。(然而事實上,代碼中使用了一些es5新增的方法,這些方法要ie9才支持,以致於咱們不得不使用es5shiv/es5sham來進行兼容);算法

靜態方法

riot.observable

riot的事件系統,全部事件通知方式都基於該模塊,可全局使用npm

// 發送全局事件

var window.eventBus = riot.observable();

eventBus.on('test', function (e) {
    console.log(e);
});

eventBus.trigger('test', 123);

包含方法數組

  • on(events, fn)
  • off(events, fn)
  • trigger(name[,arguments])
  • one(name, fn)

riot.mixin

做用是向內部對象mixins添加屬性或方法,該對象無保護,因此必需要人爲保證命名時不衝突.瀏覽器

// 在外部使用
riot.mixin('testfunction', function () { console.log(2) });

var c = riot.mixin('testfunction');

c() // print 2

該方法通常提供給riot tag初始化實例的時候使用。當在tag類中使用this.mixin混入方法的時候,會將內部對象mixins上的方法或屬性混合到tag類上緩存


riot.route

2.2.4版本的riot.route是一個功能超弱的路由管理器,經過監聽hashchange事件來觸發註冊的路由回調。該路由模塊是自動啓動的。並且它的實現上是有缺陷的。它本質上是個事件分發器。mvc

// 使用示例

riot.route(function (path, module, action, params) {
    console.log(path, module, action, params)
});

riot.route('search/index/search/1234');

包含方法

  • riot.route(arg)

    • 2.2.4版本里arg接受2種類型,字符串和function,上面已經給出示例。須要本身去分出路徑,模塊,行爲和參數。你沒看錯,就是這麼弱
  • riot.route.exec(fn)

    • 解釋當前哈希路徑,並把參數傳遞到fn裏
  • riot.route.parser(fn)

    • 指定哈希路徑解釋器,若是未調用該方法,固定解釋方法是 path.split('/');如示例所示
  • riot.route.stop()

    • 銷燬監聽hashchange事件,銷燬路由事件
  • riot.route.start()

    • 監聽。默認是開啓的

riot.util

包含兩個內容,brackets和tmpl, brackets是tmpl的輔助函數,單獨使用意義不大,該輔助函數能夠經過正則或者索引製造咱們須要匹配的部分。tmpl是riotjs的模板引擎核心,html字符串拼接徹底經過該引擎,可獨立使用(在npm上有獨立維護的模塊名爲riot-tmpl)

// 設置模板佔位符(默認是{ })
riot.settings.brackets = '{{ }}';
// 使用
var html = riot.util.tmpl('<div>{{a}}</div>', { a:1 });
console.log(html);

//print <div>1</div>

riot.tag(name, html, css, attrs, fn)

全局註冊一個riot標籤, css attrs參數可省略。其實質是向一個內部對象tagImpl上建立了一個名爲name的屬性,其值是{name,html,css,attrs,fn}。此時該緩存並無被使用,tag的實例並無創建。

riot.tag(
    'ri-root',
    [
        '<ri-login if={showLogin}></ri-login>',
        '<ri-error if={showError}></ri-error>'
    ].join(''),
    function () {
        var self = this;
        this.showLogin = false;
        this.showError = false;
        this.on('mount', function () {
            var device_id = window.Qutils.getParams('device_id');
            if (!device_id) {
                alert('參數device_id缺失!');
            }
            else {
                setTimeout(function () {
                    bridge.isInApp(
                        function () {
                            self.showLogin = true;
                            self.tags['ri-login'].trigger('login-init', device_id);
                            self.update();
                        },
                        function () {
                            self.showError = true;
                            self.update();
                        }
                    )
                }, 100);
            }
        });
    }
);

riot.mount & riot.mountTo

riot.mountTo只是riot.mount的別名。該方法顧名思義,掛在riot標籤(組件)。會返回一個tag的實例。

參數

  • selector

    • 接受'*'(mount全部), string split with ',' , string(使用原生的Selectors API,獲取一個NodeList),或者接受一個NodeList,Element
  • tagName

    • 接受'*'(mount全部), object(當爲Object類型時,即爲opts),string(等同mount全部selector上下文下的tagName匹配tag)
  • opts

    • Object,傳入的參數對象,可直接混合在tag實體的opts對象上
<!-- example -->
<div id="test"></div>
<script>
    var tag = riot.mount('#test', '*', {a:1,b:2});
    console.log(tag[0].opts.a) // print 1
</script>

riot.update

更新全部的tag實體,實質是調用每一個實體的update方法。

riot的tag實例方法

上文說到riot中所用經過riot.tag聲明的custom tag都只是緩存了,而沒有馬上產生tag實例。實際上tag實例是在執行riot.mount的時候被建立的。全部的riot tag實例都是由內部構造器Tag實例化而來的。而對於一個多tag嵌套的組件,實際上是遞歸先將子tag從底部實例化完,當實例化完成,會從根部到底部依次觸發mount事件~

this.isMounted

true | false, 指示tag是否完成安裝

this._id

一個自增的id,用於惟一表明該實例

this.parent

若一個tag實例有父實例,這個parent指向父實例

this.on('mount', function () {
    this.parent && this.parent.trigger('child-mounted');
}.bind(this))

this.root

該屬性指向tag實例所表示的真實dom元素,另外root._tag一樣掛載了tag實例的引用,因此當你的個自定義標籤實例化之後,你還能夠經過這樣的姿式找到tag實例

var tag = riot.mount('custom-tag');

console.log(tag[0].root);
// print <custom-tag></custom-tag>

console.log(document.querySelector('custom-tag')._tag)
// print Tag {xxx}

this.opts

哦,這個的構造器是Child,不過特的原型指向你傳入的opts的引用。因此若是不想本身配置被改動,請乖乖深度克隆

var tag = riot.mount('custom-tag', {a:1,b:2,c:3});

console.log(tag[0].opts.a);
// print 1

另外若是要在父子tag間傳遞參數也是很好玩的.

riot.tag(
    'hhh',
    '<zzz myoptions={this.opts.test}></zzz>',
    function () {}
);
riot.tag(
    'zzz',
    '<div>{this.opts.myoptions}</div>',
    function () {}
);
var new_custom_tag = document.createElement('hhh');
document.body.appendChild(new_custom_tag);
var custom_tag = riot.mount('hhh', {test:1});
console.log(custom_tag[0].tags['zzz'].opts.myoptions);
// print: 1

// 注: riot沒有state機制,要經過attributes傳值,當心undefined

須要注意的是,因爲他遍歷的是dom.attributes,你玩表單的時候當心一點。

this.tags

這裏面放了子tag的實例的引用,上面的示例中有相似用法。多個同名子tag會放在數組裏,我記不得在哪一個版本里了,即便是一個子tag也會放在數組裏。

this.update(data)

這個操做分爲幾個步驟:

一:源碼裏明確寫到,執行該方法先判斷data對象裏有沒有可能覆蓋tag實例屬性的屬性,若是有,丟棄。注意,該處過濾數據使用的是淺複製,若是是對象套對象,你要當心了。

二:若是是循環產生的tag(注意,若是不是在custom-tag上使用each循環產生,不會去繼承,由於此時isLoop爲undefined),從新從父tag獲取須要繼承的值

riot.tag(
    'hhh',
    '<zzz each={eee} myoptions={opts.test}></zzz>',
    function () { this.eee = [{a:1,b:2},{a:1,b:2}]; this.eeeeeeeeee = 43214321; this.fdsafsdf = 3253425432 }
);
riot.tag(
    'zzz',
    '<div>{a} {b}</div>',
    function () { this.fffff = 4325345342543}
);
var new_custom_tag = document.createElement('hhh');
document.body.appendChild(new_custom_tag);
var custom_tag = riot.mount('hhh', {test:1});
console.log(custom_tag[0].tags.zzz[0].fdsafsdf)
// print 3253425432
riot.tag(
    'hhh',
    '<div each={eee}><zzz myoptions={opts.test}></zzz></div>',
    function () { this.eee = [{a:1,b:2},{a:1,b:2}]; this.eeeeeeeeee = 43214321; this.fdsafsdf = 3253425432 }
);
riot.tag(
    'zzz',
    '<div>{a} {b}</div>',
    function () { this.fffff = 4325345342543}
);
var new_custom_tag = document.createElement('hhh');
document.body.appendChild(new_custom_tag);
var custom_tag = riot.mount('hhh', {test:1});
console.log(custom_tag[0].tags.zzz[0].fdsafsdf)
// print undefined

該特性可能會對您形成困擾,啥時候誤操做均可能一頭霧水不造爲何。

三:混合其餘數據和屬性到當前tag上

四:更新視圖,刪除dom傳導屬性,重置事件。(因此說若是你瀏覽器在dom回收和事件回收上有問題,那你更新的時候就至關捉急了,在最新的版本里把這個泄漏點給堵上了)

this.mixin()

接受無數多個字符串參數,內部運行 riot.mixin[arguments[i]]將須要混入的屬性或方法混入到實例上~~前面介紹過了。在2.2.4之前的版本沒有使用.bind(this)來參入做用域,略蛋疼的說,2.2.4 對混入的方法都bind了當前做用域。另外,注意init是很特殊的,在混入時會自動執行。

riot.mixin({
    init: function () {
        this.a = 1;
        console.log('init')
    }
});

riot.tag('test', '<div></div>', function () {
    this.mixin('init');
});

var a = document.createElement('test');
document.body.appendChild(a);
var custom_tag = riot.mount('test');
console.log(custom_tag[0].a)
// print 1

this.mount()

將該實例強制從新裝載一遍

this.unmount(keepRootTag)

傳入參數,若是爲true,會把初始化用的那個根節點也刪球掉。該方法用於卸載實例,釋放內存。

on, off, trigger, one

經過riot.observable混入的事件方法,而後咱們能夠在不一樣tag實例上處處傳播事件了,建議使用一個集線器把事件管理起來,或者使用其餘玩意,好比riot-flux什麼的來玩。

生命週期

to be continue

後記

這個框架跟虛擬dom沒撒關係,由於徹底沒有diff算法。。。在更新視圖的時候用了文檔碎片湊~,效果還湊合

相關文章
相關標籤/搜索