-
Notifications
You must be signed in to change notification settings - Fork 4
/
03-templates.md.erb
224 lines (152 loc) · 12.5 KB
/
03-templates.md.erb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
---
title: Templates
slug: templates
date: 0003/01/01
number: 3
contents: 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....
paragraphs: 44
---
Để 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:
~~~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" class="row-fluid">
{{> postsList}}
</div>
</div>
</body>
~~~
<%= caption "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.
<% note do %>
### Tìm kiếm file
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.
<% end %>
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:
~~~html
<template name="postsList">
<div class="posts">
{{#each posts}}
{{> postItem}}
{{/each}}
</div>
</template>
~~~
<%= caption "client/templates/posts/posts_list.html" %>
Và `post_item.html`với nội dung như sau:
~~~html
<template name="postItem">
<div class="post">
<div class="post-content">
<h3><a href="{{url}}">{{title}}</a><span>{{domain}}</span></h3>
</div>
</div>
</template>
~~~
<%= caption "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"), *expressions* và *block 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}}`.
<% note do %>
### Tìm hiểu hơn nữa
Bạn có thể tham khảo [tài liệu Spacebars] (https://github.com/meteor/meteor/blob/devel/packages/spacebars/README.md) nếu muốn tìm hiểu thêm về Spacebars.
<% end %>
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.
<% note do %>
### 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.
<% end %>
Để 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:
~~~js
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
});
~~~
<%= caption "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:
<%= screenshot "3-1", "Our first templates with static data" %>
Chúng tôi đang làm hai việc ở đây. Đầu tiên, chúng tôi đang thiết lập một số dữ liệu mẫu dummy trong mảng `postsData`. Dữ liệu mà thông thường sẽ đến từ các cơ sở dữ liệu, nhưng kể từ khi chúng tôi đã không nhìn thấy như thế nào để làm điều đó chưa (chờ cho chương tiếp theo!), Chúng tôi đang "gian lận" bằng cách sử dụng dữ liệu tĩnh.
Thứ hai, chúng tôi đang sử dụng `Template.postsList.helpers Meteor ()` chức năng để tạo ra một helper mẫu gọi là `posts` trả về` postsData` mảng chúng ta vừa định nghĩa ở trên.
Nếu bạn còn nhớ, chúng ta đang sử dụng là `posts` helper trong template ` postsList`:
~~~html
<template name="postsList">
<div class="posts">
{{#each posts}}
{{> postItem}}
{{/each}}
</div>
</template>
~~~
<%= caption "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." %>
### The `domain` Helper
Tương tự như vậy, chúng ta sẽ tạo `post_item.js` để giữ logic của template `postItem`:
~~~js
Template.postItem.helpers({
domain: function() {
var a = document.createElement('a');
a.href = this.url;
return a.hostname;
}
});
~~~
<%= caption "client/templates/posts/post_item.js" %>
Lần này giá trị `domain` helper của chúng tôi không phải là một mảng, nhưng một chức năng vô danh. Mô hình này là phổ biến hơn nhiều (và hữu dụng hơn) so với trước đây được đơn giản hóa ví dụ dữ liệu giả của chúng tôi.
<%= screenshot "3-2", "Displaying domains for each links." %>
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ào`this` 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`." %>
<% note do %>
### 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
<% end %>
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!
<% note do %>
### 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
<% end %>