鍍金池/ 教程/ HTML/ 會話
投票
發(fā)布和訂閱
添加用戶
簡介
會話
錯(cuò)誤
開始
路由
高級的響應(yīng)性
編輯帖子
響應(yīng)式
動畫
部署
Notifications
允許與拒絕
評論
創(chuàng)建帖子
非規(guī)范化
高級發(fā)布機(jī)制
使用 Git 和 GitHub
更進(jìn)一步
延時(shí)補(bǔ)償
集合
分頁
創(chuàng)建 Meteor Package
模版

會話

Meteor 是一個(gè)響應(yīng)式框架。這意味著隨著數(shù)據(jù)的變化, App 的改變并不需要你顯式地做任何事情。

事實(shí)上,我們已經(jīng)看到過我們的模板是如何根據(jù)數(shù)據(jù)和路由規(guī)則的變化去進(jìn)行改變的。

我們將在后面的章節(jié)去深入了解這里面是如何工作的,但我們現(xiàn)在想介紹一些基本的響應(yīng)性功能,它對于普通的 App 是非常有用的。

Meteor 的會話(Session)

現(xiàn)在在 Microscope 下,用戶在 App 中的當(dāng)前狀態(tài)是完全包含在 URL 里面,并且需要從 URL (或者數(shù)據(jù)庫)里面尋找。

但是在許多情況下,你需要存儲一些只對應(yīng)于當(dāng)前用戶的應(yīng)用程序版本的短暫狀態(tài)(例如,一個(gè)元素是否顯示或隱藏)。利用 Session 可以很方便地去做到這一點(diǎn)。

Session 是一個(gè)全局的響應(yīng)式數(shù)據(jù)存儲。它全局性的意思是全局的單例對象:這個(gè) Session 對象在全局都是可被訪問到。全局變量通常被認(rèn)為不是一件什么好事,不過在剛才的例子上,Session 可以作為中央通信總線用于項(xiàng)目的不同地方。

修改會話(Session)

會話 Session 是全局可訪問的。設(shè)置一個(gè) Session 的值,你可以調(diào)用:

? Session.set('pageTitle', 'A different title');

瀏覽器控制臺(Browser console)

通過 Session.get('mySessionProperty'); 你可以重新讀取數(shù)據(jù)的內(nèi)容,這是一個(gè)響應(yīng)式的數(shù)據(jù)源,這意味著如果你把它放在一個(gè) Helper 里面,你會看到 Helper 根據(jù) Session 變量的改變而響應(yīng)式地改變它的輸出。

讓我們試一試,將下面的代碼添加到布局模板:

<header class="navbar navbar-default" role="navigation"> 
  <div class="navbar-header">
    <a class="navbar-brand" href="{{pathFor 'postsList'}}">{{pageTitle}}</a>
  </div>
</header>

client/templates/application/layout.html

Template.layout.helpers({
  pageTitle: function() { return Session.get('pageTitle'); }
});

client/templates/application/layout.js

關(guān)于附錄(Sidebar)的代碼

請注意在附錄章節(jié)中的代碼并不是本書主流程的一部分。所以要么創(chuàng)建一個(gè)新分支(如果你使用 Git),要么確保在本章結(jié)束后恢復(fù)你所做的改動。

Meteor 的自動重載(即使用后面講到的“動態(tài)代碼重載技術(shù)”(HCR)的頁面自動刷新)會保存 Session 的變量,所以我們現(xiàn)在應(yīng)該看到“不同的標(biāo)題”顯示在導(dǎo)航欄中。如果不是,再次輸入之前的 Session.set() 命令。

另外,如果我們?nèi)ジ乃闹担ㄔ俅卧跒g覽器控制臺中),我們應(yīng)該看到另一個(gè)標(biāo)題顯示:

? Session.set('pageTitle', 'A brand new title');

Browser console

由于 Session 的全局可訪問性,所以這些變化可以作用到應(yīng)用程序的任何地方。這給了我們很大的權(quán)力,但如果使用太多也可以是一個(gè)陷阱。

另外,重點(diǎn)指出的是 Session 對象不在用戶之間共享,甚至在瀏覽器標(biāo)簽之間。這就是為什么如果現(xiàn)在你在新瀏覽器標(biāo)簽打開你的應(yīng)用,你會看到一個(gè)空網(wǎng)站標(biāo)題。

相同的變化

如果你通過 Session.set() 去修改一個(gè) Session 變量,并將其修改為相同的值,Meteor 會非常聰明的繞過繁瑣的操作,避免不必要的方法調(diào)用。

自動運(yùn)行(Autorun)

我們看到響應(yīng)式數(shù)據(jù)源的一個(gè)例子,并且看到了它在一個(gè)模板 Helper 里面的運(yùn)作。盡管某些情況下 Meteor(如模板 Helper)是響應(yīng)式的,但是大部分的 Meteor App 仍然是基于普通的非響應(yīng)式的 JavaScript 代碼。

讓我們假設(shè)有以下的代碼片段在我們的 App:

helloWorld = function() {
  alert(Session.get('message'));
}

盡管我們調(diào)用一個(gè)響應(yīng)式會話(Session)變量,但它并不是在響應(yīng)式的上下文中調(diào)用,所以當(dāng)改變這個(gè) Session 變量的時(shí)候,我們也不會自動運(yùn)行 alert 函數(shù)。

這個(gè)時(shí)候,就要引入自動運(yùn)行(Autorun)機(jī)制了。顧名思義,每一次 autorun 上下文中的響應(yīng)式數(shù)據(jù)源發(fā)生變化的時(shí)候,autorun 函數(shù)就會自動運(yùn)行。

嘗試到瀏覽器控制臺輸入:

? Tracker.autorun( function() { console.log('Value is: ' + Session.get('pageTitle')); } );
Value is: A brand new title

瀏覽器控制臺(Browser console)

如你所料,放在 autorun 函數(shù)里面的代碼將會運(yùn)行一次,把數(shù)據(jù)輸出到控制臺。現(xiàn)在,讓我們嘗試去改變標(biāo)題:

? Session.set('pageTitle', 'Yet another value');
Value is: Yet another value

瀏覽器控制臺(Browser console)

神奇吧!隨著 Session 變量的改變, autorun 知道它必須重新運(yùn)行自己的代碼,并把新的值重新輸出到控制臺。

所以我們回到之前的例子,如果希望每次 Session 變量發(fā)生變化的時(shí)候引發(fā)新的警報(bào)(alert),我們需要做的就是將我們的代碼封裝在 autorun 函數(shù)里面:

Tracker.autorun(function() {
  alert(Session.get('message'));
});

正如我們前面看到的,autorun 會自動跟蹤響應(yīng)式數(shù)據(jù)源,在它們變化的時(shí)候作出響應(yīng)的反應(yīng)。

動態(tài)代碼重載技術(shù)

在 Microscope 的開發(fā)過程中,我們已經(jīng)用過 Meteor 的動態(tài)代碼重載技術(shù)(HCR)去節(jié)省時(shí)間:當(dāng)我們修改并保存一個(gè)源代碼的文件后,Meteor 會立刻檢測到變化,直接重啟正在運(yùn)行的 Meteor 服務(wù)器,并通知每個(gè)客戶端重新加載該頁面。

這類似于頁面的自動刷新,但有一個(gè)很重要的差異。

為了找出那是什么,先重置一下之前改過的 Session 變量:

? Session.set('pageTitle', 'A brand new title');
? Session.get('pageTitle');
'A brand new title'

瀏覽器控制臺(Browser console)

如果我們手動去重載瀏覽器窗口,自然就會丟失我們的 Session 變量(因?yàn)檫@將會創(chuàng)建一個(gè)新的會話)。另一方面,如果我們是引發(fā)動態(tài)代碼重載(即,通過修改并保存我們的源文件)去重新加載頁面,Session 變量卻仍然存在?,F(xiàn)在去試一試!

? Session.get('pageTitle');
'A brand new title'

瀏覽器控制臺(Browser console)

因此,如果使用 Session 變量來保存用戶狀態(tài),用戶幾乎不會察覺到動態(tài)代碼重載的發(fā)生。因?yàn)樗鼘⒈A羲?Session 變量的值。這可以使我們在部署新版本的時(shí)候,用戶發(fā)生中斷的機(jī)會降到最低。

再想一想,這意味著,只要我們做到用 URL 和 Session 把所有狀態(tài)保存下來,那么當(dāng)更新版本的時(shí)候,客戶端正在運(yùn)行的應(yīng)用程序就可以動態(tài)重載,不丟失任何數(shù)據(jù)。

現(xiàn)在去檢驗(yàn)一下當(dāng)我們?nèi)ナ謩铀⑿马撁娴臅r(shí)候發(fā)生了什么:

? Session.get('pageTitle');
null

瀏覽器控制臺(Browser console)

當(dāng)我們重載頁面時(shí),我們丟失了 Session 。在 HCR 中,Meteor 將 Session 保存到瀏覽器的本地存儲并且在重載的之后再一次加載它。然而,在重載頁面時(shí)發(fā)生的丟失行為是有一定道理的:如果用戶重新加載頁面,就好像他們已經(jīng)再次瀏覽相同的 URL ,而且其他用戶都會看到他們訪問的 URL,所以他們應(yīng)該重置為初始狀態(tài)。

從中我們應(yīng)該要學(xué)會:

  1. 應(yīng)該在 Session 或者 URL 中存儲用戶狀態(tài)。從而在動態(tài)代碼重載的時(shí)候,讓用戶發(fā)生中斷的機(jī)會降到最低。
  2. 盡可能使用 URL 去存儲你想要共享在用戶之間的狀態(tài)。

以上總結(jié)了我們對會話(Session)——— Meteor 最有用的功能之一的探索。不要忘了在進(jìn)行下一章之前,恢復(fù)你對代碼的改動。