11/08/2018, 19:48

Discover Meteor - Chương 4 (Templates)

Trong chương này bạn sẽ: Tìm hiểu về ngôn ngữ templating Meteor, Spacebars Tạo ba mẫu đầu tiên của bạn Tìm hiểu cách quản lý công việc Meteor Nhận một nguyên mẫu cơ bản làm việc với các dữ liệu tĩnh Để dễ dàng vào phát triển Meteor, chúng ta sẽ áp dụng một phương pháp tiếp cận từ ...

Trong chương này bạn sẽ:

  • Tìm hiểu về ngôn ngữ templating Meteor, Spacebars
  • Tạo ba mẫu đầu tiên của bạn
  • Tìm hiểu cách quản lý công việc Meteor
  • Nhận một nguyên mẫu cơ bản làm việc với các dữ liệu tĩnh

Để dễ dàng vào phát triển Meteor, chúng ta sẽ áp dụng một phương pháp tiếp cận từ ngoài vào trong. Nói cách khác, chúng ta sẽ xây dựng một HTML / JavaScript "dump" bao bọc bên ngoài, và sau đó gắn nó vào bên trong ứng dụng của chúng ta.

Điều này có nghĩa là trong chương này chúng ta sẽ chỉ để quan tâm đến những gì đang xảy ra bên trong thư mục /client.

Nếu bạn vẫn chưa tạo, hãy bắt đầu bằng việc tạo ra một file tên là main.html bên trong thư mục /client và thêm vào đoạn code sau:

<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" class="row-fluid">
      {{> postsList}}
    </div>
  </div>
</body>

client/main.html

Đây sẽ là template chính cho ứng dụng của chúng ta. Như bạn có thể nhìn thấy đoạn code hầu như là HTML ngoại trừ tag {{> postsList}} mục đích để thêm template vào, nó chèn vào template postsList tới ngay sau đây. Bây giờ, hãy cùng tạo ra một vài template nữa.

Meteor Templates

Về mặt cốt lõi, một trang tin tức mạng xã hội được kết cấu từ những bài viết sắp xếp thành danh sách, và đó cũng sẽ là điều mà chúng ta sẽ làm với các templete.

Hãy tạo một thư mục / templates bên trong / client. Đây sẽ là nơi chúng ta đặt tất cả template vào, và để giữ cho mọi thứ gọn gàng, chúng tôi cũng sẽ tạo ra thư mục / posts bên trong/ templates để lưu trữ những template liên quan đến việc post bài viết.

Tìm kiếm files

Meteor rất giỏi trong việc tìm kiếm file. Bất kể bạn đặt code ở đâu trong thư mục /client, Meteor sẽ tìm và biên dịch nó theo đúng chuẩn. Điều này có nghĩa là, bạn sẽ không cần phải viết đoạn mã để thêm vào đường dẫn cho các file JavaScript hay là CSS.

Điều này cũng có nghĩa là bạn có thể đặt tất cả file trong cùng một thư mục, hoặc thậm trí tất cả code trong cùng một file. Nhưng vì Meteor sẽ biên dịch mọi thứ thành một file đơn nhất đã được làm nhỏ (minify), chúng ta nên giữ cho mọi thứ được cấu trúc và sẽ dùng cấu trúc file sạch sẽ hơn

Cuối cùng thì chúng ta đã sẵn sàng để tạo ra template thứ hai. Bên trong thư mục client / templates / posts, tạo ra file posts_list.html với nội dung như sau:

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

client/templates/posts/posts_list.html

Và post_item.htmlvới nội dung như sau:

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

client/templates/posts/post_item.html

Lưu ý đến thuộc tính name =" postsList " của phần tử template. Đây là tên sẽ được sử dụng bởi Meteor để biết được template nào đang ở đâu (chú ý răng tên thực của file không liên quan).

Bây giờ, hãy cùng xem xét tới hệ thống Template của Meteor, là Spacebars. Spacebars đơn giản chỉ là HTML, với ba thứ được thêm vào: inclusions (cũng được biết đến như là "partials"), expressionsblock helpers.

Inclusions sử dụng cú pháp {{> templateName}} , công việc của nó đơn giản chỉ là bảo Meteor thay thế đoạn mã với template tương ứng (trong trường hợp của chúng ta là postItem).

Biểu thức , ví dụ như là {{title}} hoặc là gọi đến một thuộc tính của object hiện tại, hoặc là trả về giá trị của một template helper đã được định nghĩa trong trình quản lý template (sẽ tìm hiểu sau).

Cuối cùng, block helper là những tag đặc biệt điều khiển luồng của template, ví dụ như {{#each}}…{{/each}} hoặc {{#if}}…{{/if}}.

Tìm hiểm hơn nữa

Bạn có thể tham khảo tài liệu Spacebars nếu muốn tìm hiểu thêm về Spacebars.

Gắn kết những kiến thức kể trên, chúng ta có thể bắt đầu hiểu những gì đang xảy ra ở đây.

Đầu tiên, trong template postsList, chúng ta lặp qua object post với block helper {{#each}}…{{/each}}. Sau đó, với mỗi thành phần, chúng ta thêm vào template postItem.

Vậy template postItem này tới từ đâu? Đây là một câu hỏi hay. Nó thực ra là một template helper, và bạn có thể suy nghĩ nó như là một chỗ giữ cho giá trị thay đổi.

Bản thân template postItem khá là dễ hiểu. Nó chỉ dùng đúng ba biểu thức: {{url}} và {{title}} đều trả về thuộc tính của tài liệu, và {{domain}}gọi tới tempalte helper.

Template Helpers

Cho đến bây giờ, chúng ta đã làm việc với Spacebars, thứ thực ra là HTML nhưng với một vài tag thêm vào. Không giống như ngôn ngữ khác, như PHP chẳng hạn (hoặc như HTML thuần, có thể chứa JavaScript), Meteor giữ template và phần logic độc lập, và những template này bản thân nó thực tế không làm nhiều việc.

Theo trình tự, một template cần có helper. Bạn có thể nghĩ helper như là những người đầu bếp lấy nguyên liệu thô (dữ liệu của bạn) và chuẩn bị chúng, trước khi truyền ra đĩa (template) tới người phục vụ, là người sẽ đưa ra cho bạn.

Nói cách khác, trong khi mục đích của template giới hạn trong việc hiển thị hoặc tạo vòng lặp trên các biến, helper là người thực sự làm công việc phức tạp gán giá trị cho các biến.

Controllers?

Có thể bạn sẽ nghĩ theo hướng file chứa helper cho một template là một controller. Nhưng điều đó có thể không thực sự chính xác, vì controller (trong mô hình MVC) thường làm công việc khác một chút.

Vì vậy mà chúng tôi quyết định tránh việc dùng thuật ngữ đó, và đơn giản gọi là "template helper" hoặc "logic cho template" khi nói về code JavaScript cho một template.

Để mọi thứ được đơn giản, chúng ta sẽ dùng giữ luật đặt tên file chứa helper của một template giống tên của template, nhưng với đuôi là .js. Vậy hãy cùng tạo ra file posts_list.js bên trong thư mục /client/templates/posts và bắt đầu viết helper đầu tiên:

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
});

client/templates/posts/posts_list.js

Nếu bạn thực hành đúng, bạn sẽ thấy màn hình như sau trong trình duyệt:

Ở đây, chúng ta đã thực hiện hai việc. Đầu tiên, chúng ta thiết lập một bộ dữ liệu dummy trong mảng postsArray. Dữ liệu đó sẽ tới từ cơ sở dữ liệu, nhưng vì chúng ta vẫn chưa biết làm thế nào để thực hiện điều đó (cho tới chương tiếp theo), chúng ta sẽ dùng tạm thời dữ liệu cố định.

Tiếp theo, chúng ta sử dụng hàm Template.postsList.helpers() của Meteor để tạo ra template helper tên là posts trả về dữ liệu của mảng postsData mà chúng ta đã định nghĩa trước đó.

Nếu bạn còn nhớ, chúng ta đang sử dụng là posts helper trong template postsList:

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

client/templates/posts/posts_list.html

Với việc định nghĩa helper posts, điều đó có nghĩa là chúng ta có thể sử dụng cho template, do đó template của chúng ta sẽ có thể lặp qua mảng postData và đưa vào mỗi object tương ứng template postItem.

commit "3-1" - Added basic posts list template and static data
Xem trên GitHub
Xem trực tuyến

domain Helper

Tương tự như vậy, chúng ta sẽ tạo post_item.js để giữ logic của template postItem:

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

client/templates/posts/post_item.js

Lần này, giá trị cho helper domain của chúng ta không phải là một mảng, mà là một hàm không định danh. Pattern này thường được dùng nhiều hơn so với ví dụ đơn giản về dữ liệu dummy trước đó.

Helper domain nhận một URL và trả về domain thông qua JavaScript. Nhưng ngay từ ban đầu, từ đâu nó có thể nhận url?

Để trả lời câu hỏi này, chúng ta cần phải quay lại template posts_list.html. Block helper {{#each}} không chỉ lặp lại trên mảng, mà nó còn thiết lập giá trị của this bên trong block vào object lặp tương ứng.

Điều này có nghĩa là giữa hai tag {{#each}}, mỗi bài viết được gán vàothis lần lượt, và điều đó mở rộng tất cả mọi thứ bên trong trình quản lý template (post_item.js).

Bây giờ chúng ta đã hiểu tại sao this.url trả về URL của bài viết hiện tại. Hơn thế nữa, nếu chúng ta dùng {{title}} và {{url}}bên trong template post_item, Meteor biết được rằng chúng ta muốn chỉ this.title và this.url và trả về giá trị đúng đắn.

commit "3-2" - "Setup a domain helper on the postItem.
Xem trên GitHub
Xem trực tuyến

JavaScript Magic

Mặc dù điều này không phải chỉ riêng có ở Meteor, đây là một giải thích ngắn gọn về đoạn code JavaScript ở trên. Đầu tiên, chúng ta tạo ra một thành phần HTML (a) rỗng, và lưu trữ trong bộ nhớ.

Sau đó, chúng ta thiết lập href bằng với URl của bài viết hiện tại (như chúng ta đã thấy trước đó, nó là một helper this trong object đang được trỏ tới).

Cuối cùng, chúng ta sử dụng thuộc tính hostname của thành phần a để quay trở lại đường dẫn domain mà không cần toàn bộ URL

Nếu bạn đã theo dõi xuyên suốt hướng dẫn, bạn sẽ thấy được một danh sách bài viết trong trình duyệt. Danh sách đó đơn giản chỉ là dữ liệu tĩnh, vì vậy mà nó không sử dụng tính năng real-time của Meteor. Và chúng ta sẽ biết cách làm điều này trong chương kế tiếp!

Hot Code Reload

Bạn có thể thấy rằng bạn thậm chí không cần phải tự tải lại cửa sổ trình duyệt của bạn bất cứ khi nào bạn thay đổi một tập tin.
Điều này là bởi vì Meteor theo dõi tất cả các file trong thư mục dự án của bạn, và tự động làm mới trình duyệt của bạn mỗi khi nó phát hiện ra sự thay đổi nào đó.
Hot Code Reload của Meteor khá là thông minh, nó thậm trí còn cung cấp trang thái của ứng dụng giữa mỗi lần làm mới

0