Khối điều kiện {#if}
Để thực hiện渲染 có điều kiện (conditional rendering) trong Svelte, bạn có thể sử dụng khối {#if}. Cú pháp cơ bản bao gồm các nhánh {:else if} và {:else} để xử lý các trường hợp khác nhau.
{#if userScore === 100}
<p>Kết quả hoàn hảo!</p>
{/if}
Bạn có thể kết hợp nhiều điều kiện và thêm nhánh mặc định ở cuối:
{#if water.temp > 50}
<p>Nước quá nóng!</p>
{:else if 20 > water.temp}
<p>Nước quá lạnh!</p>
{:else}
<p>Nhiệt độ vừa phải</p>
{/if}
Lưu ý rằng các khối logic này không chỉ bọc các phần tử HTML, mà còn có thể bọc các đoạn văn bản thông thường bên trong phần tử.
Khối lặp {#each}
Khối {#each} được sử dụng để duyệt qua các danh sách. Nguồn dữ liệu có thể là mảng, đối tượng tương tự mảng (có thuộc tính length), hoặc các đối tượng có thể lặp như Map và Set.
<h1>Danh sách công việc</h1>
<ul>
{#each tasks as task}
<li>{task.title} - Ưu tiên: {task.priority}</li>
{/each}
</ul>
Tương tự như hàm map trong JavaScript, bạn cũng có thể lấy chỉ số (index) của vòng lặp hiện tại:
{#each tasks as task, idx}
<li>{idx + 1}: {task.title} - Ưu tiên: {task.priority}</li>
{/each}
Sử dụng Key với {#each}
Khi cung cấp một biểu thức key duy nhất cho mỗi phần tử, Svelte sẽ dựa vào đó để so sánh sự khác biệt khi dữ liệu thay đổi, thay vì chỉ thêm/xóa ở cuối danh sách. Khóa nên là chuỗi hoặc số để đảm bảo tính ổn định.
{#each tasks as task (task.uid)}
<li>{task.title} - Ưu tiên: {task.priority}</li>
{/each}
<!-- Kết hợp với chỉ số -->
{#each tasks as task, idx (task.uid)}
<li>{idx + 1}: {task.title} - Ưu tiên: {task.priority}</li>
{/each}
Svelte cho phép bạn áp dụng cú pháp destructuring và rest pattern bên trong khối {#each}:
{#each tasks as { uid, title, priority }, idx (uid)}
<li>{idx + 1}: {title} - Ưu tiên: {priority}</li>
{/each}
{#each records as { uid, ...details }}
<li><span>{uid}</span><TaskCard {...details} /></li>
{/each}
{#each matrix as [id, ...remaining]}
<li><span>{id}</span><DataView items={remaining} /></li>
{/each}
Lặp không có biến đại diện
Nếu bạn chỉ muốn lặp lại một đoạn nội dung n lần mà không cần tham chiếu đến phần tử, có thể bỏ qua phần as:
<div class="grid-board">
{#each { length: 4 }, row}
{#each { length: 4 }, col}
<div class:active={(row + col) % 2 === 0}></div>
{/each}
{/each}
</div>
Xử lý danh sách rỗng với {:else}
Khối {#each} hỗ trợ nhánh {:else}, nội dung bên trong nhánh này sẽ được hiển thị khi danh sách không có phần tử nào:
{#each tasks as task}
<p>{task.title}</p>
{:else}
<p>Không có công việc nào!</p>
{/each}
Khối {#key}
Khi giá trị của biểu thức bên trong {#key} thay đổi, Svelte sẽ hủy và tạo lại toàn bộ nội dung bên trong khối. Điều này rất hữu ích để ép component phải khởi tạo lại từ đầu:
{#key currentId}
<UserProfile />
{/key}
Ngoài ra, nó cũng là cách tuyệt vời để kích hoạt lại các hiệu ứng chuyển động (transition) khi giá trị cập nhật:
{#key activeTab}
<div transition:slide>{activeTab}</div>
{/key}
Khối bất đồng bộ {#await}
Khối {#await} cho phép bạn xử lý trực tiếp các Promise trong template với ba trạng thái: đang chờ (pending), đã hoàn thành (fulfilled), và bị từ chối (rejected).
{#await fetchData}
<!-- Trạng thái pending -->
<p>Đang tải dữ liệu...</p>
{:then result}
<!-- Trạng thái fulfilled -->
<p>Kết quả: {result}</p>
{:catch err}
<!-- Trạng thái rejected -->
<p>Lỗi: {err.message}</p>
{/await}
Lưu ý: Trong quá trình Server-Side Rendering (SSR), chỉ có nhánh trạng thái "đang chờ" được render. Nếu biểu thức không phải là một
Promise, chỉ nhánh:thensẽ được hiển thị, kể cả khi đang SSR.
Nếu bạn không cần xử lý lỗi, nhánh catch có thể được bỏ qua:
{#await fetchData}
<p>Đang tải dữ liệu...</p>
{:then result}
<p>Kết quả: {result}</p>
{/await}
Nếu không cần hiển thị trạng thái chờ, bạn có thể bỏ qua khối ban đầu:
{#await fetchData then result}
<p>Kết quả: {result}</p>
{/await}
Tương tự, nếu chỉ quan tâm đến lỗi, bạn có thể bỏ qua then:
{#await fetchData catch err}
<p>Lỗi xảy ra: {err}</p>
{/await}
Mẹo: Bạn có thể kết hợp
#awaitvớiimport(...)để tải component một cách lười biếng (lazy loading):{#await import('./UserProfile.svelte') then { default: Profile }} <Profile /> {/await}