Riot - 你的下一個(gè)框架

前端孟抗,你是文藝界的程序員

我為什么要用Riot

?優(yōu)點(diǎn)明顯润匙,體積小惊暴,加載快,繼承了react趁桃,Polymer等框架的優(yōu)勢(shì),并簡(jiǎn)化他們肄鸽,主要從以下幾個(gè)方面考慮:

1. 自定義標(biāo)簽卫病。

?Riot 在所有瀏覽器上支持自定義標(biāo)簽,我們能將頁面組件化典徘,一個(gè)自定義標(biāo)簽結(jié)構(gòu)如下所示:

<todo>
  <!--布局-->
  <h3>{ item }</h3>

  <!-- css -->
  <style scoped>
    h3 { font-size: 14px; }
  </style>

  <!-- 業(yè)務(wù)邏輯 -->
  <script>
    var self = this;
    self.item = ‘Riot sample’;
  </script>
</todo>
2. 對(duì)閱讀友好

?有了自定義標(biāo)簽功能后蟀苛,我們可以用很簡(jiǎn)潔語言‘拼湊’出復(fù)雜的用戶界面,加上語義化標(biāo)簽定義逮诲,在閱讀的時(shí)候帜平,很容易看清楚哪個(gè)標(biāo)簽是給html加入了什么組件,一共有多少個(gè)組件梅鹦,這樣一個(gè)頁面大致實(shí)現(xiàn)什么功能裆甩,甚至不用看瀏覽器展示都能明白。你的代碼可能是這樣的

<body>
  <h1>Acme community</h1>
  <forum-header/>
  <forum-content>
    <forum-threads/>
    <forum-sidebar/>
  </forum-content>
  <forum-footer/>
  <script>riot.mount('*', { api: forum_api })</script>
</body>

?很清楚齐唆,頁面被分成四三個(gè)模塊嗤栓,一個(gè)標(biāo)題h1,一個(gè)header,一個(gè)content和一個(gè)footer茉帅,這樣就在我們腦海構(gòu)成一個(gè)基礎(chǔ)的網(wǎng)頁模型
?Riot 標(biāo)簽首先被 編譯 成標(biāo)準(zhǔn) JavaScript叨叙,然后在瀏覽器中運(yùn)行。

3. 虛擬 DOM
  • 保證最少量的DOM 更新和數(shù)據(jù)流動(dòng)
  • 單向數(shù)據(jù)流: 更新和刪除操作由父組件向子組件傳播
  • 表達(dá)式會(huì)進(jìn)行預(yù)編譯和緩存以保證性能
  • 為更精細(xì)的控制提供生命周期事件
  • 支持自定義標(biāo)簽的服務(wù)端渲染堪澎,支持單語言應(yīng)用
4. 與標(biāo)準(zhǔn)保持一致
  • 沒有專有的事件系統(tǒng)
  • 渲染出的 DOM 節(jié)點(diǎn)可以放心地用其它工具(庫)進(jìn)行操作
  • 不要求額外的 HTML 根元素或 data- 屬性
  • 與 jQuery 友好共存

5. 友好的語法

(1).強(qiáng)大的簡(jiǎn)寫語法

class={ enabled: is_enabled, hidden: hasError() }

(2).語義化強(qiáng)擂错,不需要費(fèi)腦記憶

render, state, constructor 或 shouldComponentUpdate

(3).直接插值

Add #{ items.length + 1 } 或 class="item { selected: flag }"

(4).用 <script> 標(biāo)簽來包含邏輯代碼不是必需的
(5).緊湊的 ES6 方法定義語法

6. 麻雀小,五臟全

最小化是 Riot 區(qū)別于其它庫的重要特點(diǎn)樱蛤,它所提供的 API 方法比其他庫要少 10 至 100倍钮呀。
?react.min.js – 34.89KB
?polymer.min.js – 49.38KB
?riot.min.js – 10.38KB

Riot 擁有創(chuàng)建現(xiàn)代客戶端應(yīng)用的所有必需的成分:

  • “響應(yīng)式” 視圖層用來創(chuàng)建用戶界面
  • 用來在各獨(dú)立模塊之間進(jìn)行通信的事件庫
  • 用來管理URL和瀏覽器回退按鈕的路由器(Router

?

學(xué)前三兩個(gè)FAQ

1. 標(biāo)簽名中必須使用橫線 (-) 嗎?

?W3C 規(guī)范要求在標(biāo)簽名中使用橫線。所以 <person> 需要寫成 <my-person>. 如果你關(guān)心 W3C 的話就遵循這個(gè)規(guī)則. 其實(shí)兩者都能跑

2. 為什么源碼中沒有分號(hào)?

?不寫分號(hào)使代碼更整潔刹悴。這與我們的整體的最小化哲學(xué)是一致的行楞。同樣的原因,我們使用單引號(hào)土匀,也建議你在使用riot時(shí)不要使用分號(hào)和雙引號(hào)子房。

3. 為什么使用 == 運(yùn)算符?

?運(yùn)算符本身沒有好壞之分,如果你知道它的工作原理就轧,巧妙的使用能簡(jiǎn)化你的代碼证杭,如node.nodeValue = value == null ? '' : value 這將導(dǎo)致 0false 被顯示而 nullundefined 顯示為空字符串。這正是我們想要的妒御!

4. 使用 onclick解愤?

?onclick只是比較‘過時(shí)’。將JS和HTML放在同一個(gè)模塊里比美學(xué)重要乎莉。Riot的最小化語法使事件處理器看起來很象樣兒送讲。


?

開始學(xué)習(xí) Riot

一、自定義標(biāo)簽

1. 直觀感受

?Riot 自定義標(biāo)簽是構(gòu)建用戶界面的單元惋啃。它們構(gòu)成了應(yīng)用的”視圖”部分哼鬓。我們先從一個(gè)實(shí)現(xiàn)TODO應(yīng)用的例子來感受一下Riot的各個(gè)功能:(自定義標(biāo)簽會(huì)被 編譯 成 JavaScript.)

<todo>
  <h3>{ opts.title }</h3>
  
  <ul>
    <li each={ items }>
      <label class={ completed: done }>
        <input type="checkbox" checked={ done } onclick={ parent.toggle }> { title }
      </label>
    </li>
  </ul>
  
  <form onsubmit={ add }>
    <input name="input" onkeyup={ edit }>
    <button disabled={ !text }>Add #{ items.length + 1 }</button>
  </form>

  <script>
    this.disabled = true
    this.items = opts.items
    edit(e) {
      this.text = e.target.value
    }
    add(e) {
      if (this.text) {
        this.items.push({ title: this.text })
        this.text = this.input.value = ''
      }
    }
    toggle(e) {
      var item = e.item
      item.done = !item.done
      return true
    }
  </script>
</todo>
2. 標(biāo)簽語法

Riot標(biāo)簽是布局(HTML)與邏輯(JavaScript)的組合。以下是基本的規(guī)則:

  • 先定義HTML边灭,然后將邏輯包含在一個(gè)可選的 <script> 標(biāo)簽里. 注意: 如果在document body里包含標(biāo)簽定義异希,則不能使用 script 標(biāo)簽,它只能用于外部標(biāo)簽文件中
  • 如果不寫 <script> 標(biāo)簽绒瘦,則最后一個(gè) HTML 標(biāo)簽結(jié)束的位置被認(rèn)為是 JavaScript 代碼是開始称簿。
  • 自定義標(biāo)簽可以是空的,可以只有HTML惰帽,也可以只有 JavaScript
  • 標(biāo)簽屬性值的引號(hào)是可選的: <foo bar={ baz }> 會(huì)被理解成 <foo bar="{ baz }">.
  • 支持ES6 方法語法: methodName() 會(huì)被理解成 this.methodName = function() 憨降,this 變量總是指向當(dāng)前標(biāo)簽實(shí)例。
  • 可以使用針對(duì) class 名的簡(jiǎn)化語法: 當(dāng) done 的值是 true時(shí)善茎,class={ completed: done } 將被渲染成 class="completed"券册。
  • 如果表達(dá)式的值不為真值,則布爾型的屬性(checked, selected 等等..)將不被渲染: <input checked={ undefined }> 的渲染結(jié)果是 <input>.
  • 所有的屬性名必須是小寫. 這是由于瀏覽器的限制。
  • 支持自關(guān)閉標(biāo)簽: <div/> 等價(jià)于 <div></div>. 那些眾所周知的 “不關(guān)閉標(biāo)簽” 如 <br>, <hr>, <img> or <input> 在編譯后總是不關(guān)閉的烁焙。
  • 自定義標(biāo)簽需要被關(guān)閉(正常關(guān)閉航邢,或自關(guān)閉)。
  • 標(biāo)準(zhǔn) HTML tags (label, table, a 等..) 也可以被自定義骄蝇,但并不建議這么做膳殷。

注意: 自定義標(biāo)簽文件里的標(biāo)簽定義總是從某一行的行首開始,前面不能放空格九火。內(nèi)置標(biāo)簽定義(定義在 document body中) 必須正確縮進(jìn)赚窃,所有的自定義標(biāo)簽擁有相同的最低級(jí)的縮進(jìn)級(jí)別, 不建議將tab與空格混合使用

<!--正確-->
<t-tag>
</t-tag>

<!--正確-->
<t-tag></t-tag>

<!--錯(cuò)誤 沒從行首開始-->
  <t-tag>
  </t-tag>
3. 省略 script 標(biāo)簽

?可以省略 <script> 標(biāo)簽,如果這么做岔激,邏輯會(huì)認(rèn)為從最后一個(gè) HTML 標(biāo)簽結(jié)束處開始

<todo>
  <!-- 布局 -->
  <h3>{ opts.title }</h3>
  // 邏輯
  this.items = [1, 2, 3]
</todo>
4. 預(yù)處理

?可以使用 type 屬性來指定預(yù)處理器. 現(xiàn)在可選的type值包括“coffee”, “typescript”, “es6”“none”. 也可以為 language 加上 “text/” 前綴, 如 “text/coffee”

<script type="coffee">
  # coffeescript 標(biāo)簽邏輯
</script>
5. 標(biāo)簽 css

?在標(biāo)簽內(nèi)部可以放置一個(gè) style 標(biāo)簽勒极,Riot.js 會(huì)自動(dòng)將它提取出來并放到 <head> 部分,因?yàn)榉诺搅薶ead部分虑鼎,所以其他文件也能調(diào)用到該樣式

<todo>
  <!-- 布局 -->
  <h3>{ opts.title }</h3>

  <style>
    todo { display: block }
    todo h3 { font-size: 120% }
    /** 本標(biāo)簽其它專有的css **/
  </style>
</todo>
6. 局部 CSS

?支持局部 CSS 辱匿。

<todo>
  <!-- 布局 -->
  <h3>{ opts.title }</h3>

  <style scoped>
    :scope { display: block }
    h3 { font-size: 120% }
    /** 本標(biāo)簽其它專有的css **/
  </style>
</todo>

?css的提取和移動(dòng)只執(zhí)行一次,無論此自定義標(biāo)簽被初始化多少次炫彩。 為了能夠方便地覆蓋CSS匾七,你可以指定Riot在<head>中的哪個(gè)位置插入標(biāo)簽所定義的css:

<style type="riot"></style>

?例如,在某些場(chǎng)景下可以指定將riot組件庫的標(biāo)簽css放在normalize.css后面江兢,而放在網(wǎng)站的整體主題CSS之前昨忆,這樣可以覆蓋組件庫的默認(rèn)風(fēng)格。
?

二杉允、自定義標(biāo)簽的加載

1. 直觀體驗(yàn)

?自定義標(biāo)簽實(shí)例被創(chuàng)建后邑贴,就可以象這樣將其加載到頁面上:

<body>

  <!-- 將自定義標(biāo)簽放在body內(nèi)部的任何地方 -->
  <todo></todo>

  <!-- 引入 riot.js -->
  <script src="riot.min.js"></script>

  <!-- 引入標(biāo)簽定義文件 -->
  <script src="todo.js" type="riot/tag"></script>

  <!-- 加載標(biāo)簽實(shí)例 -->
  <script>riot.mount('todo')</script>

</body>

?放置在頁面 body 中的自定義標(biāo)簽必須使用正常關(guān)閉方式: <todo></todo> ,自關(guān)閉的寫法: <todo/> 不支持叔磷。

2. mount 方法的使用方法

?將自定義標(biāo)簽放在 <body> 后痢缎,我們還需要調(diào)用riot.mount()才能將其加載進(jìn)來。一個(gè)html文檔中可以包含一個(gè)自定義標(biāo)簽的多個(gè)實(shí)例世澜。

// mount 頁面中所有的自定義標(biāo)簽
riot.mount('*')

// mount 自定義標(biāo)簽到指定id的html元素
riot.mount('#my-element')

// mount 自定義標(biāo)簽到選擇器選中的html元素
riot.mount('todo, forum, comments')
3. 標(biāo)簽生命周期

自定義標(biāo)簽的創(chuàng)建過程是這樣的:

  1. 創(chuàng)建標(biāo)簽實(shí)例
  2. 標(biāo)簽定義中的JavaScript被執(zhí)行
  3. HTML 中的表達(dá)式被首次計(jì)算并首次觸發(fā) “update” 事件
  4. 標(biāo)簽被加載 (mount) 到頁面上,觸發(fā) “mount” 事件

加載完成后署穗,表達(dá)式會(huì)在以下時(shí)機(jī)被更新:

  1. 當(dāng)一個(gè)事件處理器被調(diào)用(如上面ToDo示例中的toggle方法)后自動(dòng)更新寥裂。你也可以在事件處理器中設(shè)置 e.preventUpdate = true 來禁止這種行為。
  2. 當(dāng)前標(biāo)簽實(shí)例的 this.update() 方法被調(diào)用時(shí)
  3. 當(dāng)前標(biāo)簽的任何一個(gè)祖先的 this.update() 被調(diào)用時(shí). 更新從父親到兒子單向傳播案疲。
  4. 當(dāng) riot.update() 方法被調(diào)用時(shí), 會(huì)更新頁面上所有的表達(dá)式封恰。

每次標(biāo)簽實(shí)例被更新,都會(huì)觸發(fā)“update” 事件褐啡。
由于表達(dá)式的首次計(jì)算發(fā)生在加載之前诺舔,所以不會(huì)有類似 <img src={ src }> 計(jì)算失敗之類的意外問題。

4. 監(jiān)聽生命周期事件

標(biāo)簽定義內(nèi)部可以這樣監(jiān)聽各種生命周期事件:

<todo>
  this.on('before-mount', function() {
    // 標(biāo)簽被加載之前
  })

  this.on('mount', function() {
    // 標(biāo)簽實(shí)例被加載到頁面上以后
  })

  this.on('update', function() {
    // 允許在更新之前重新計(jì)算上下文數(shù)據(jù)
  })

  this.on('updated', function() {
      // 標(biāo)簽?zāi)0甯潞?    })

  this.on('before-unmount', function() {
    // 標(biāo)簽實(shí)例被刪除之前
  })

  this.on('unmount', function() {
    // 標(biāo)簽實(shí)例被從頁面上刪除后
  })

  // 想監(jiān)聽所有事件?
  this.on('all', function(eventName) {
    console.info(eventName)
  })
</todo>
5. 訪問 DOM 元素

?Riot 允許開發(fā)人員通過 this 實(shí)例直接訪問設(shè)置了 name 屬性的元素低飒,也提供了各種簡(jiǎn)化的屬性方法如 if="{...}"许昨,但偶爾你還是需要直接完成這些內(nèi)置手段所不支持的DOM操作。

6. 如何使用 jQuery, Zepto, querySelector, 等等

?如果需要在Riot中訪問DOM,要注意 DOM 元素的初始化發(fā)生在第一個(gè) update() 事件被觸發(fā)之后褥赊,這意味著在這之前試圖選擇這個(gè)元素將都失敗糕档。

<example-tag>
  <p id="findMe">Do I even Exist?</p>

  <script>
  var test1 = document.getElementById('findMe')
  console.log('test1', test1)  // 失敗

  this.on('update', function(){
    var test2 = document.getElementById('findMe')
    console.log('test2', test2) // 成功
  })
  </script>
</example-tag>

?你可能并不打算在每次update時(shí)都去取一下你想要的元素,而更傾向于在 mount 事件中做這件事拌喉。

<example-tag>
  <p id="findMe">Do I even Exist?</p>

  <script>
  var test1 = document.getElementById('findMe')
  console.log('test1', test1)  // 失敗

  this.on('update', function(){
    var test2 = document.getElementById('findMe')
    console.log('test2', test2) // 成功速那,每次更新都會(huì)觸發(fā)
  })

  this.on('mount', function(){
    var test3 = document.getElementById('findMe')
    console.log('test3', test3) // 成功,實(shí)例被加載以后尿背,只觸發(fā)一次
  })
  </script>
</example-tag>
7. 基于上下文的 DOM 查詢

?現(xiàn)在我們知道了如何在處理 updatemount 事件時(shí)獲取 DOM 元素端仰,現(xiàn)在我們可以利用這一點(diǎn),將 根元素 (我們所創(chuàng)建的 riot 標(biāo)簽實(shí)例) 作為DOM元素查詢的上下文田藐。

<example-tag>
  <p id="findMe">Do I even Exist?</p>
  <p>Is this real life?</p>
  <p>Or just fantasy?</p>

  <script>
  this.on('mount', function(){
    // Contexted jQuery
    $('p', this.root)

    // Contexted Query Selector
    this.root.querySelectorAll('p')
  })
  </script>
</example-tag>
8. 標(biāo)簽選項(xiàng)(參數(shù))

?mount 方法的第二個(gè)參數(shù)用來傳遞標(biāo)簽選項(xiàng)

<script>
  riot.mount('todo', { title: 'My TODO app', items: [ ... ] })
</script>

?在標(biāo)簽內(nèi)部荔烧,通過 opts 變量來訪問這些參數(shù),如下:

<my-tag>
  <!-- 在HTML中訪問參數(shù) -->
  <h3>{ opts.title }</h3>

  // 在 JavaScript 中訪問參數(shù)
  var title = opts.title
</my-tag>
9. Mixin

?Mixin 可以將公共代碼不同標(biāo)簽之間方便地共享坞淮。

var OptsMixin = {
    init: function() {
      this.on('updated', function() { console.log('Updated!') })
    },

    getOpts: function() {
        return this.opts
    },

    setOpts: function(opts, update) {
        this.opts = opts

        if(!update) {
            this.update()
        }

        return this
    }
}

<my-tag>
    <h1>{ opts.title }</h1>

    this.mixin(OptsMixin)   // 用 mixin() 加上mixin名字來將mixin混入標(biāo)簽.
</my-tag>

?上例中茴晋,我們?yōu)樗?my-tag 標(biāo)簽實(shí)例混入了 OptsMixin ,它提供 getOptssetOpts 方法. init 是個(gè)特殊方法回窘,用來在標(biāo)簽載入時(shí)對(duì)mixin進(jìn)行初始化诺擅。 (init 方法不能混入此mixin的標(biāo)簽中訪問)

var my_tag_instance = riot.mount('my-tag')[0]

console.log(my_tag_instance.getOpts()) // 輸出<my-tag>的所有的標(biāo)簽選項(xiàng)

?標(biāo)簽的mixin可以是 object – {'key': 'val'} var mix = new function(...) – 混入任何其它類型的東西將報(bào)錯(cuò).

?現(xiàn)在:my-tag 定義又加入了一個(gè) getId 方法,以及OptMixin中除init以外的所有其它方法

function IdMixin() {
    this.getId = function() {
        return this._id
    }
}

var id_mixin_instance = new IdMixin()

<my-tag>
    <h1>{ opts.title }</h1>

    this.mixin(OptsMixin, id_mixin_instance)
</my-tag>

?由于定義在標(biāo)簽這個(gè)級(jí)別啡直,mixin不僅僅擴(kuò)展了你的標(biāo)簽的功能, 也能夠在重復(fù)的界面中使用. 每次標(biāo)簽被加載時(shí)烁涌,即使是子標(biāo)簽, 標(biāo)簽實(shí)例也獲得了mixin中的代碼功能.

10. 共享 mixin

?為了能夠在文件之間和項(xiàng)目之間共享mixin,提供了 riot.mixin API. 你可以像這樣全局性地注冊(cè)mixin :

riot.mixin('mixinName', mixinObject)

用 mixin() 加上mixin名字來將mixin混入標(biāo)簽.

<my-tag>
    <h1>{ opts.title }</h1>

    this.mixin('mixinName')
</my-tag>

?

表達(dá)式

1, 直觀理解

在 HTML 中可以混合寫入表達(dá)式酒觅,用花括號(hào)括起來撮执。[ style 標(biāo)簽中的表達(dá)式將被忽略.]

{ /* 某個(gè)表達(dá)式 */ }

表達(dá)式可以放在html屬性里,也可以作為文本節(jié)點(diǎn)嵌入:

<h3 id={ /* 屬性表達(dá)式 */ }>
  { /* 嵌入表達(dá)式 */ }   // 文本節(jié)點(diǎn)
</h3>

當(dāng)然舷丹,并不是什么表達(dá)式都是能嵌入抒钱,因?yàn)镽iot只支持屬性(值)表達(dá)式和嵌入的文本表達(dá)式,以下將會(huì)執(zhí)行失敗颜凯。

<input type="checkbox" { true ? 'checked' : ''}>

表達(dá)式是 100% 純 JavaScript. 一些例子:

{ title || 'Untitled' }
{ results ? 'ready' : 'loading' }
{ new Date() }
{ message.length > 140 && 'Message is too long' }
{ Math.round(rating) }

?建議的設(shè)計(jì)方法是使表達(dá)式保持最簡(jiǎn)從而使你的HTML盡量干凈谋币。如果你的表達(dá)式變得太復(fù)雜,建議你考慮將它的邏輯轉(zhuǎn)移到 “update” 事件的處理邏輯中. 例如:

<my-tag>
  <!-- `val` 的值在下面的代碼中計(jì)算 .. -->
  <p>{ val }</p>

  // 每次更新時(shí)計(jì)算
  this.on('update', function() {
    this.val = some / complex * expression ^ here
  })
</my-tag>
2. 布爾屬性

如果表達(dá)式的值為非真症概,則布爾屬性 (checked, selected 等..) 將不被渲染:
<input checked={ null }> 渲染為<input>
這與 W3C 有很大區(qū)別蕾额,W3C規(guī)范是只要布爾屬性存在即為true,即使他的值為或者false

3. class 屬性簡(jiǎn)化寫法

Riot 為 CSS class 名稱提供了特殊語法. 看一個(gè)例子

<p class={ foo: true, bar: 0, baz: new Date(), zorro: 'a value' }></p>

該表達(dá)式最終被計(jì)算為 “foo baz zorro”.彼城,只有表達(dá)式中為真值的屬性名會(huì)被加入到class名稱列表中. 這種用法并不限于用在計(jì)算class名稱的場(chǎng)合诅蝶。

4. 轉(zhuǎn)義

用以下的寫法來對(duì)花括號(hào)進(jìn)行轉(zhuǎn)義:

\\{ this is not evaluated \\}  輸出為  { this is not evaluated }
5. 渲染原始HTML

Riot 表達(dá)式只能渲染不帶HTML格式的文本值退个。如果真的需要,可以寫一個(gè)自定義標(biāo)簽來做這件事. 例如:

<raw>
  <span></span>

  this.root.innerHTML = opts.content
</raw>

這個(gè)標(biāo)簽定義以后调炬,可以被用在其它的標(biāo)簽里. 例如

<my-tag>
  <p>原始HTML: <raw content="{ html }"/> </p>

  this.html = 'Hello, <strong>world!</strong>'
</my-tag>

?

嵌套標(biāo)簽

我們來定義一個(gè)父標(biāo)簽 <account> 语盈,其中嵌套一個(gè)子標(biāo)簽 <subscription>:

<account>
  <subscription  plan={ opts.plan } show_details="true" />
</account>

// 子標(biāo)簽
<subscription>
  <h3>{ opts.plan.name }</h3>

  // 取得標(biāo)簽選項(xiàng)
  var plan = opts.plan, 
      show_details = opts.show_details   // 取出子標(biāo)簽的標(biāo)簽屬性

  // 訪問父標(biāo)簽實(shí)例
  var parent = this.parent   // 獲取父標(biāo)簽的標(biāo)簽實(shí)例

</subscription>

注意: 我們使用下劃線的風(fēng)格(而不是駝峰風(fēng)格)對(duì) show_details 進(jìn)行命名,由于瀏覽器的約定筐眷,駝峰風(fēng)格的命名會(huì)被自動(dòng)轉(zhuǎn)換成小寫.
如果在頁面上加載 account 標(biāo)簽黎烈,帶 plan 選項(xiàng),調(diào)用riot.mount()方法匀谣。

<body>
  <account></account>
</body>

<script>
  riot.mount('account', { plan: { name: 'small', term: 'monthly' } })
</script>

注意: 嵌套的標(biāo)簽只能定義在自定義父標(biāo)簽里照棋,如果定義在頁面上,將不會(huì)被初始化武翎。


?

嵌套 HTML

“HTML transclusion” 是處理頁面上標(biāo)簽內(nèi)部 HTML 的方法. 通過內(nèi)置的 <yield> 標(biāo)簽來實(shí)現(xiàn).

<my-tag>
  <p>Hello <yield/></p>
  this.text = 'world'
</my-tag>

頁面上放置自定義標(biāo)簽烈炭,并包含嵌套的 HTML

<my-tag>
  <b>{ text }</b>
</my-tag>

結(jié)果得到

<my-tag>
  <p>Hello <b>world</b><p>
</my-tag>

?

DOM元素與name自動(dòng)綁定

?我感覺這個(gè)功能真的是帥炸了。當(dāng)html被定義好了之后宝恶,帶有 ref 屬性的DOM元素將自動(dòng)被綁定到上下文中符隙,這樣就可以從JavaScript中方便地訪問它們:

<login>
  <form ref="login" onsubmit={ submit }>
    <input ref="username">
    <input ref="password">
    <button ref="submit">
  </form>

  // 獲取 HTML 元素
  var form = this.refs.login,
    username = this.refs.username.value,
    password = this.refs.password.value,
    button = this.refs.submit

</login>

當(dāng)然,因?yàn)镈OM已經(jīng)被綁定到上下文中垫毙,所以我們也可以直接在HTML中以表達(dá)式形式引用:

<div>{ username.value }</div>

?

事件處理器

1. 一般處理

響應(yīng)DOM事件的函數(shù)稱為 “事件處理器”.

<login>
  <form onsubmit={ submit }>
  </form>

  // 上面的表單提交時(shí)調(diào)用此方法
  submit(e) {

  }
</login>

?以”on” (onclick, onsubmit, oninput等…)開頭的屬性的值是一個(gè)函數(shù)名霹疫,當(dāng)相應(yīng)的事件發(fā)生時(shí),此函數(shù)被調(diào)用. 函數(shù)也可以通過表達(dá)式來動(dòng)態(tài)定義:

<form onsubmit={ condition ? method_a : method_b }>

?在此函數(shù)中综芥,this指向當(dāng)前標(biāo)簽實(shí)例丽蝎。當(dāng)處理器被調(diào)用之后, this.update() 將被自動(dòng)調(diào)用膀藐,將所有可能的變化體現(xiàn)到 UI 上屠阻。

2. 阻止默認(rèn)行為

?如果事件的目標(biāo)元素不是checkboxradio按鈕,默認(rèn)的事件處理器行為是 自動(dòng)取消事件 . 意思是它總會(huì)自動(dòng)調(diào)用 e.preventDefault() , 因?yàn)橥ǔ6夹枰{(diào)用它额各,而且容易被遺忘国觉。如果要讓瀏覽器執(zhí)行默認(rèn)的操作,在處理器中返回 true 就可以了.

submit() {
  return true
}
3. 事件對(duì)象

?事件處理器的第一個(gè)參數(shù)是標(biāo)準(zhǔn)的事件對(duì)象虾啦。事件對(duì)象的以下屬性已經(jīng)被Riot進(jìn)行了跨瀏覽器兼容

  • e.currentTarget 指向事件處理器的所屬元素.
  • e.target 是發(fā)起事件的元素麻诀,與 currentTarget 不一定相同.
  • e.which 是鍵盤事件(keypress, keyup, 等…)中的鍵值 .
  • e.item循環(huán) 中的當(dāng)前元素.

?

渲染條件 - show / hide / if

可以基于條件來決定顯示或隱藏元素。例如:

<div if={ is_premium }>
  <p>This is for premium users only</p>
</div>

同樣, 渲染條件中的表達(dá)式也可以是一個(gè)簡(jiǎn)單屬性傲醉,或一個(gè)完整的 JavaScript 表達(dá)式. 有以下選擇:

  • show – 當(dāng)值為真時(shí)用 style="display: ''" 顯示元素
  • hide – 當(dāng)值為真時(shí)用 style="display: none" 隱藏元素
  • if – 在 document 中添加 (真值) 或刪除 (假值) 元素

判斷用的操作符是 == 而非 ===. 例如: 'a string' == true.


?

循環(huán)

1. 循環(huán)是用 each 屬性來實(shí)現(xiàn):
<todo>
  <ul>
    <li each={ items } class={ completed: done }>
      <input type="checkbox" checked={ done }> { title }
    </li>
  </ul>

  this.items = [
    { title: 'First item', done: true },
    { title: 'Second item' },
    { title: 'Third item' }
  ]
</todo>

?定義 each 屬性的html元素根據(jù)對(duì)數(shù)組中的所有項(xiàng)進(jìn)行重復(fù)针饥。 當(dāng)數(shù)組使用 push(), slice()splice 方法進(jìn)行操作后,新的元素將被自動(dòng)添加或刪除需频。

2. 上下文

?循環(huán)中的每一項(xiàng)將創(chuàng)建一個(gè)新的上下文(標(biāo)簽實(shí)例);如果有嵌套的循環(huán)筷凤,循環(huán)中的子標(biāo)簽都會(huì)繼承父循環(huán)中定義了而自己未定義的屬性和方法昭殉。Riot通過這種方法來避免重寫不應(yīng)在父標(biāo)簽中重寫的東西苞七。
?從子上下文中可以通過顯式地調(diào)用 parent 變量來訪問上級(jí)上下文.

<todo>
  <div each={ items }>
    <h3>{ title }</h3>
    <a onclick={ parent.remove }>Remove</a>
  </div>

  this.items = [ { title: 'First' }, { title: 'Second' } ]
  remove(event) {

  }
</todo>

?該例中,除了 each 屬性外挪丢,其它都屬于子上下文, 因此 title 可以被直接訪問而 remove 需要從 parent. 中訪問蹂风,因?yàn)?code>remove方法并不是循環(huán)元素的屬性.
?每一個(gè)循環(huán)項(xiàng)都是一個(gè)標(biāo)簽實(shí)例. Riot 不會(huì)修改原始數(shù)據(jù)項(xiàng),因此不會(huì)為其添加新的屬性乾蓬。

3. 循環(huán)項(xiàng)的事件處理器

事件處理器中可以通過 event.item 來訪問單個(gè)集合項(xiàng)惠啄。這種辦法采用了事件委托機(jī)制,極大減少了對(duì)DOM的訪問任内。
下面我們來實(shí)現(xiàn)上方的 remove 函數(shù):

<todo>
  <div each={ items }>
    <h3>{ title }</h3>
    <a onclick={ parent.remove }>Remove</a>
  </div>

  this.items = [ { title: 'First' }, { title: 'Second' } ]

  remove(event) {

    // 循環(huán)項(xiàng)
    var item = event.item

    // 在集合中的索引
    var index = this.items.indexOf(item)

    // 從集合中刪除
    this.items.splice(index, 1)
  }
</todo>

?事件處理器被執(zhí)行后撵渡,當(dāng)前標(biāo)簽實(shí)例會(huì)自動(dòng)調(diào)用 this.update()(你也可以在事件處理器中設(shè)置 e.preventUpdate = true 來禁止這種行為)從而導(dǎo)致所有循環(huán)項(xiàng)也被更新. 父親會(huì)發(fā)現(xiàn)集合中被刪除了一項(xiàng),從而將對(duì)應(yīng)的DOM結(jié)點(diǎn)從document中刪除死嗦。

4. 循環(huán)自定義標(biāo)簽

自定義標(biāo)簽也可以被循環(huán)

<todo-item each="{ items }" data="{ this }"></todo-item>

當(dāng)前循環(huán)項(xiàng)可以用 this 來引用趋距,你可以用它來將循環(huán)項(xiàng)作為一個(gè)參數(shù)傳遞給循環(huán)標(biāo)簽。

5. 非對(duì)象數(shù)組

數(shù)組元素不要求是對(duì)象. 也可以是字符串或數(shù)字. 這時(shí)可以用 { name, i in items } 寫法

<my-tag>
  <p each="{ name, i in arr }">{ i }: { name }</p>

  this.arr = [ true, 110, Math.random(), 'fourth']
</my-tag>

name 是元素的名字越除,i 是索引. 這兩個(gè)變量的變量名可以自由選擇节腐。

6. 對(duì)象循環(huán)

也可以對(duì)普通對(duì)象做循環(huán). 例如:

<my-tag>
  <p each="{ name, value in obj }">{ name } = { value }</p>

  this.obj = {
    key1: 'value1',
    key2: 1110.8900,
    key3: Math.random()
  }
</my-tag>

?不太建議使用對(duì)象循環(huán),因?yàn)樵趦?nèi)部實(shí)現(xiàn)中摘盆,Riot使用 JSON.stringify 來探測(cè)對(duì)象內(nèi)容的改變. 整個(gè) 對(duì)象都會(huì)被檢查翼雀,只要有一處改變,整個(gè)循環(huán)將會(huì)被重新渲染. 會(huì)很慢. 普通的數(shù)組要快得多孩擂,而且只有變化的部分會(huì)在頁面上體現(xiàn)狼渊。

7. 循環(huán)的高級(jí)技巧

?在 riot v2.3 中,為了使循環(huán)渲染更可靠肋殴,DOM 結(jié)點(diǎn)的移動(dòng)囤锉,插入和刪除總是與數(shù)據(jù)集合同步的: 這種策略會(huì)導(dǎo)致渲染過程比之前的版本慢一些。要使用更快的渲染算法护锤,可以在循環(huán)結(jié)點(diǎn)上加上 no-reorder 屬性官地。

<loop>
  <div each="{ item in items }" no-reorder>{ item }</div>
</loop>

?

使用標(biāo)準(zhǔn) HTML 元素作為標(biāo)簽 | #riot-tag

頁面body中的標(biāo)準(zhǔn) HTML 元素也可以作為riot標(biāo)簽來使用,只要加上 riot-tag 屬性.

<ul riot-tag="my-tag"></ul>

這為用戶提供了一種選擇烙懦,與css框架的兼容性更好. 這些標(biāo)簽將被與其它自定義標(biāo)簽一樣進(jìn)行處理驱入。

riot.mount('my-tag')

會(huì)將 my-tag 標(biāo)簽 加載到 ul 元素上


?

服務(wù)端渲染 | #server-side

Riot 支持服務(wù)端渲染,使用 Node/io.js 可以方便地引用標(biāo)簽定義并渲染成 html:

var riot = require('riot')
var timer = require('timer.tag')

var html = riot.render(timer, { start: 42 })

console.log(html) // <timer><p>Seconds Elapsed: 42</p></timer>

循環(huán)和條件渲染都支持.

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末氯析,一起剝皮案震驚了整個(gè)濱河市亏较,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌掩缓,老刑警劉巖育韩,帶你破解...
    沈念sama閱讀 222,252評(píng)論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異伏蚊,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)尘执,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,886評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來宴凉,“玉大人誊锭,你說我怎么就攤上這事∶殖” “怎么了丧靡?”我有些...
    開封第一講書人閱讀 168,814評(píng)論 0 361
  • 文/不壞的土叔 我叫張陵,是天一觀的道長籽暇。 經(jīng)常有香客問我温治,道長,這世上最難降的妖魔是什么图仓? 我笑而不...
    開封第一講書人閱讀 59,869評(píng)論 1 299
  • 正文 為了忘掉前任罐盔,我火速辦了婚禮,結(jié)果婚禮上救崔,老公的妹妹穿的比我還像新娘惶看。我一直安慰自己,他們只是感情好六孵,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,888評(píng)論 6 398
  • 文/花漫 我一把揭開白布纬黎。 她就那樣靜靜地躺著,像睡著了一般劫窒。 火紅的嫁衣襯著肌膚如雪本今。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,475評(píng)論 1 312
  • 那天主巍,我揣著相機(jī)與錄音冠息,去河邊找鬼。 笑死孕索,一個(gè)胖子當(dāng)著我的面吹牛逛艰,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播搞旭,決...
    沈念sama閱讀 41,010評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼散怖,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了肄渗?” 一聲冷哼從身側(cè)響起镇眷,我...
    開封第一講書人閱讀 39,924評(píng)論 0 277
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎翎嫡,沒想到半個(gè)月后欠动,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,469評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡惑申,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,552評(píng)論 3 342
  • 正文 我和宋清朗相戀三年具伍,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了铆遭。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,680評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡沿猜,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出碗脊,到底是詐尸還是另有隱情啼肩,我是刑警寧澤,帶...
    沈念sama閱讀 36,362評(píng)論 5 351
  • 正文 年R本政府宣布衙伶,位于F島的核電站祈坠,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏矢劲。R本人自食惡果不足惜赦拘,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,037評(píng)論 3 335
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望芬沉。 院中可真熱鬧躺同,春花似錦、人聲如沸丸逸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,519評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽黄刚。三九已至捎谨,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間憔维,已是汗流浹背涛救。 一陣腳步聲響...
    開封第一講書人閱讀 33,621評(píng)論 1 274
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留业扒,地道東北人检吆。 一個(gè)月前我還...
    沈念sama閱讀 49,099評(píng)論 3 378
  • 正文 我出身青樓,卻偏偏與公主長得像凶赁,于是被迫代替她去往敵國和親咧栗。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,691評(píng)論 2 361

推薦閱讀更多精彩內(nèi)容

  • 問答題47 /72 常見瀏覽器兼容性問題與解決方案虱肄? 參考答案 (1)瀏覽器兼容問題一:不同瀏覽器的標(biāo)簽?zāi)J(rèn)的外補(bǔ)...
    _Yfling閱讀 13,760評(píng)論 1 92
  • HTML標(biāo)簽解釋大全 一致板、HTML標(biāo)記 標(biāo)簽:!DOCTYPE 說明:指定了 HTML 文檔遵循的文檔類型定義(D...
    米塔塔閱讀 3,260評(píng)論 1 41
  • 這篇筆記主要包含 Vue 2 不同于 Vue 1 或者特有的內(nèi)容,還有我對(duì)于 Vue 1.0 印象不深的內(nèi)容咏窿。關(guān)于...
    云之外閱讀 5,052評(píng)論 0 29
  • 1.安裝 可以簡(jiǎn)單地在頁面引入Vue.js作為獨(dú)立版本斟或,Vue即被注冊(cè)為全局變量,可以在頁面使用了集嵌。 如果希望搭建...
    Awey閱讀 11,034評(píng)論 4 129
  • 今天七夕節(jié)萝挤,七夕快樂御毅! 知道嗎,曾經(jīng)幻想過無數(shù)個(gè)與你一起過七夕的場(chǎng)景怜珍,到今天也沒有機(jī)會(huì)實(shí)現(xiàn)端蛆。 分開之后我才漸漸明白...
    甜了個(gè)醬閱讀 277評(píng)論 0 0