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

模版

為了更容易地進(jìn)入 Meteor 的開發(fā),我們將采用從外向內(nèi)的方法來搭建項(xiàng)目。換句話說,我們將首先建立一個(gè) HTML/JavaScript 的外殼,然后把它放到我們的項(xiàng)目里,內(nèi)部細(xì)節(jié)處理稍后再說。

這意味著在本章中,我們只關(guān)注 /client 目錄里面的事情。

讓我們先在 /client 目錄創(chuàng)建一個(gè) main.html 文件,并寫入以下代碼:

<head>
  <title>Microscope</title>
</head>
<body>
  <div class="container">
    <header class="navbar navbar-default" role="navigation"> 
      <div class="navbar-header">
        <a class="navbar-brand" href="/">Microscope</a>
      </div>
    </header>
    <div id="main">
      {{> postsList}}
    </div>
  </div>
</body>

這是我們主要的 App 模板。在上面看到很多熟悉的 HTML 標(biāo)簽,除了這個(gè) {{> postsList}} 標(biāo)簽,它是 postsList 模板的插入點(diǎn),等一下我們就會(huì)說到。現(xiàn)在,先讓我們創(chuàng)建更多的模板吧。

Meteor 模板

我們項(xiàng)目的核心是社會(huì)新聞網(wǎng)站,它是由一系列的帖子所組成的,而這正是我們要調(diào)用模板的原因。

我們先在 /client 里面創(chuàng)建一個(gè) /templates 目錄。這里用來放我們所有的模板,這樣可以保持項(xiàng)目結(jié)構(gòu)的清晰整潔,接著在 /templates 里面再創(chuàng)建 /posts 目錄來存放與帖子相關(guān)的模板。

查找文件

Meteor 的強(qiáng)大之處在于文件的查找。無論你把代碼文件放在 /client 目錄下的任何地方,Meteor 都可以找到它并且正確地進(jìn)行編譯。這意味著你永遠(yuǎn)都不需要手動(dòng)編寫 JavaScript 或 CSS 文件的調(diào)用路徑。

這也意味著你可能會(huì)把所有的文件放在同一目錄,甚至所有的代碼放在同一個(gè)文件。但由于 Meteor 會(huì)把一切的代碼都編譯到一個(gè)壓縮的文件里面,因此我們更偏向于把項(xiàng)目弄得井井有條,使用更整潔的文件結(jié)構(gòu),提高項(xiàng)目的可讀性。

接下來我們開始創(chuàng)建第二個(gè)模板。在 client/templates/posts 目錄中,創(chuàng)建 posts_list.html :

<template name="postsList">
  <div class="posts">
    {{#each posts}}
      {{> postItem}}
    {{/each}}
  </div>
</template>

post_item.html

<template name="postItem">
  <div class="post">
    <div class="post-content">
      <h3><a href="{{url}}">{{title}}</a><span>{{domain}}</span></h3>
    </div>
  </div>
</template>

注意模板的 name="postsList" 屬性,它的作用是告訴 Meteor 去根據(jù)這個(gè)名稱來跟蹤這個(gè)模板的位置。(注意的是實(shí)際文件的文件名不相關(guān)。)

是時(shí)候來介紹 Meteor 的模板系統(tǒng) Spacebars 了。Spacebar 就是簡(jiǎn)單的 HTML 加上三件事情:Inclusion (有時(shí)也稱作 “partial”)、ExpressionBlock Helper。

Inclusion :通過 {{> templateName}} 標(biāo)記,簡(jiǎn)單直接地告訴 Meteor 這部分需要用相同名稱的模板來取代(在我們的例子中就是 postItem )。

Expression :比如 {{title}} 標(biāo)記,它要么是調(diào)用當(dāng)前對(duì)象的屬性,要么就是對(duì)應(yīng)到當(dāng)前模板管理器中定義的 helper 方法,并返回其方法值(后面會(huì)詳細(xì)討論)。

Block Helper :在模板中控制流程的特殊標(biāo)簽,如 {{#each}}…{{/each}}{{#if}}…{{/if}} 。

進(jìn)一步學(xué)習(xí)

你如果想了解更多關(guān)于 Spacebars,可以參考 Spacebars 文檔

有了這些知識(shí),我們就可以很容易去理解了。

首先,在 postsList 模板里,我們通過 {{#each}}…{{/each}} Block Helper 去遍歷一個(gè) posts 對(duì)象。然后,每次迭代我們?nèi)グ?postItem 模板。

這個(gè) posts 對(duì)象來自哪里?好問題。它實(shí)際上是一個(gè) 模板 helper,你可以想象它是動(dòng)態(tài)值的占位符(placeholder)。

postItem 這個(gè)模板本身相當(dāng)簡(jiǎn)單。它只使用三個(gè)標(biāo)簽: {{url}}{{title}} 都返回其集合的屬性,而 {{domain}} 則調(diào)用模板對(duì)應(yīng)的 helper 方法。

模板 Helper

到目前為止我們已經(jīng)學(xué)會(huì)了使用 Spacebars ,這只是在 HTML 的基礎(chǔ)上多幾個(gè)標(biāo)簽而已。不像其他語言如 PHP (甚至常規(guī) HTML 頁面,還包含了 JavaScript), Meteor 只是讓模板和邏輯進(jìn)行分離,而這些模板本身并不需要做很多復(fù)雜的事情。

為了讓連接變得更流暢,一個(gè)模板需要 helper。你可以想象這些 helper 就是廚師用食材(你的數(shù)據(jù))烹飪好佳肴(模板),再由服務(wù)員端到你面前。

換句話說,模板的作用局限于顯示或循環(huán)變量,而 helper 則扮演著一個(gè)相當(dāng)重要的角色:把值分配給每個(gè)變量。

Contoller 控制器?

我們也許會(huì)情不自禁地認(rèn)為包含所有模板 helper 的文件是個(gè) controller(控制器)。但這是很模糊的,因?yàn)?controller (至少在 MVC 情況下)通常有些不同的作用。

所以我們決定遠(yuǎn)離那個(gè)術(shù)語,在談?wù)撽P(guān)于模板涉及的 JavaScript 代碼時(shí),就簡(jiǎn)單地稱為“模板的 helper”或是“模板的邏輯”。

為簡(jiǎn)單起見,我們將采用與模板同名的方式來命名包含其 helper 的文件,區(qū)別是 .js 擴(kuò)展名。那好讓我們馬上在 /client/templates/posts 目錄下創(chuàng)建 posts_list.js 文件,開始構(gòu)建我們第一個(gè) helper:

var postsData = [
  {
    title: 'Introducing Telescope',
    url: 'http://sachagreif.com/introducing-telescope/'
  }, 
  {
    title: 'Meteor',
    url: 'http://meteor.com'
  }, 
  {
    title: 'The Meteor Book',
    url: 'http://themeteorbook.com'
  }
];
Template.postsList.helpers({
  posts: postsData
});

如果你運(yùn)行是正確的,你現(xiàn)在應(yīng)該在瀏覽器中看到這樣的畫面:

http://wiki.jikexueyuan.com/project/discover-meteor/images/3-1.png" alt="" />

我們剛剛在做兩件事情。首先我們放置一些虛擬的基本數(shù)據(jù)到 postsData 數(shù)組中。原本數(shù)據(jù)應(yīng)該是來自數(shù)據(jù)庫的,但由于我們還沒有學(xué)習(xí)到該怎么做(下一章揭曉),所以我們先通過使用靜態(tài)數(shù)據(jù)來“作弊”。

然后,我們使用的是 Meteor 的 Template.postsList.helpers() 函數(shù),建立了 posts 模板 helper 來返回剛剛定義的 postsData 數(shù)組。

如果你記得,現(xiàn)在我們?cè)?postsList 模板中使用這個(gè) posts helper:

<template name="postsList">
  <div class="posts">
    {{#each posts}}
      {{> postItem}}
    {{/each}}
  </div>
</template>

定義 posts helper 就就讓我們的模板可以使用它,所以模板就可以遍歷 postsData 數(shù)組并將里面的每個(gè)對(duì)象發(fā)送到 postItem 模板中。

添加了基本的 post 列表模板和靜態(tài)數(shù)據(jù)

關(guān)于 domain Helper

類似地,我們現(xiàn)在創(chuàng)建一個(gè) post_item.js 文件來包含 postItem 模板的邏輯:

Template.postItem.helpers({
  domain: function() {
    var a = document.createElement('a');
    a.href = this.url;
    return a.hostname;
  }
});

這一次我們 domain helper 的值不再是一個(gè)數(shù)組,而是一個(gè)匿名函數(shù)。相比起我們之前簡(jiǎn)化的虛擬數(shù)據(jù)的例子,這種模式更為常見(而且更有用)。

http://wiki.jikexueyuan.com/project/discover-meteor/images/3-2.png" alt="" />

這個(gè) domain helper 方法通過 JavaScript 來獲取一個(gè) URL 地址并返回其域名。但是它一開始是從哪里獲得 URL 地址呢?

為了回答這個(gè)問題,我們需要回到我們的 posts_list.html 模板。{{#each}} 代碼塊不僅遍歷我們數(shù)組,它還在代碼塊范圍內(nèi)將 this 的值賦予被遍歷的對(duì)象。

這意味著在 {{#each}} 標(biāo)記之間,每個(gè) post 都可以通過 this 依次訪問,并且一直延伸到模板 helper(post_item.js)中。

我們現(xiàn)在明白了為什么 this.url 會(huì)返回當(dāng)前 post 的 URL。而且,如果我們?cè)?post_item.html 模板里面使用 {{title}}{{url}},Meteor 就會(huì)知道需要去調(diào)用 this.titlethis.url 去返回我們想要的正確值。

設(shè)置 postItemdomain helper

神奇的 JavaScript

盡管這對(duì)于 Meteor 來說并不特別,這里會(huì)簡(jiǎn)單解釋一下上面“神奇的 JavaScript 代碼”。首先,我們創(chuàng)建一個(gè)空的錨(a)HTML 標(biāo)簽并儲(chǔ)存在內(nèi)存中。

然后我們將其 href 屬性設(shè)置為當(dāng)前 post 的 URL (正如我們剛剛講到的,this 在 helper 中正是當(dāng)前被操作的對(duì)象)。

最后,我們利用 a 標(biāo)簽的特別的 hostname 屬性來返回 URL 的域名。

如果你正確地緊跟著我們的進(jìn)度,這時(shí)候你就會(huì)在瀏覽器中看到一個(gè) post 列表。但這個(gè)列表只是調(diào)用了靜態(tài)數(shù)據(jù),它沒有利用到 Meteor 實(shí)時(shí)性的特點(diǎn)。我們將在下一章向你展示該如何去修改!

動(dòng)態(tài)代碼重載

你可能已經(jīng)注意到,當(dāng)你修改文件的時(shí)候,不需要手動(dòng)刷新頁面,瀏覽器就會(huì)自動(dòng)重新加載。

這是因?yàn)?Meteor 跟蹤了項(xiàng)目目錄下的所有文件,當(dāng)檢測(cè)到其中一個(gè)文件發(fā)生改變,它就會(huì)自動(dòng)刷新你的瀏覽器。

Meteor 的動(dòng)態(tài)代碼重載是相當(dāng)智能的,它甚至可以在兩個(gè)刷新動(dòng)作之間保存你的 App 狀態(tài)。

上一篇:創(chuàng)建帖子下一篇:簡(jiǎn)介