November 11, 20237 minutes
전체 강좌 목록입니다.
** 목차 **
Hello World 컴포넌트를 만들어 보겠습니다.
Svelte 컴포넌트는 .svelte 파일 확장자를 사용합니다.
컴포넌트에는 템플릿, 스크립트, 그리고 스타일이 포함될 수 있습니다.
유효한 HTML은 유효한 Svelte 컴포넌트입니다.
아래 코드는 일반 텍스트 문자열만 있는 가장 기본적인 Svelte 컴포넌트가 있습니다.
HelloWorld.svelte
Hello, world!
HelloWorld.svelte
<p>Hello, world!</p>
Svelte는 컴포넌트를 설정하기 위해 <script>
태그를 사용합니다.
스크립트 태그에서 선언된 변수는 템플릿에서 접근할 수 있도록 만들어집니다.
일단 아래와 같이 체크박스가 있는 컴포넌트를 만들어 보겠습니다.
컴포넌트에 데이터를 추가하려면 변수가 포함된 스크립트 태그를 도입해야 합니다.
실제로 Svelte 컴포넌트에서는 스크립트(script) 태그가 파일의 맨 위에 위치합니다.
템플릿에서는 중괄호로 데이터를 출력할 수 있습니다.
데이터는 속성에서도 사용할 수 있습니다.
변수 이름이 속성과 일치하는 경우, 약식 표기법도 사용할 수 있습니다.
Todo.svelte
<script>
let checked = false;
</script>
<input type="checkbox" checked={checked}>
<input type="checkbox" {checked}>
컴포넌트는 유저인터페이스에 있어 재사용 가능한 구성 요소입니다.
Svelte 컴포넌트는 .svelte 확장자를 가진 파일에서만 작성됩니다.
이 예제에서는 Todo 컴포넌트를 만들고, 이를 TodoList 컴포넌트에서 렌더링해 보겠습니다.
컴포넌트는 내보낸 let 변수를 사용하여 다른 컴포넌트로 props을 전달하거나 받을 수 있습니다.
변수를 할당하여 기본값을 설정할 수 있습니다.
Todo.svelte
<script>
export let task;
export let completed = false;
</script>
<p>
<input type="checkbox" checked={completed} />
{task}
</p>
컴포넌트를 가져와 다른 컴포넌트에서 사용할 수 있습니다.
컴포넌트는 PascalCase로 렌더링 됩니다.
TodoList.svelte
<script>
import Todo from './Todo.svelte';
</script>
<Todo task="Lawn Mowing" />
<Todo task="Walking the Dog" />
<Todo task="Reading Newspaper" />
TodoList.svelte
<script>
import Todo from './Todo.svelte';
let task = "Lawn Mowing";
</script>
<Todo {task} />
...
를 사용하여 여러 props를 한꺼번에 전달할 수 있습니다.TodoList.svelte
<script>
import Todo from './Todo.svelte';
let todo = {
task: "Lawn Mowing",
completed: false,
};
</script>
<Todo {...todo} />
Svelte는 {#each}
및 {#if}
템플릿 지시문(디렉티브-directive)을 사용하여 목록을 렌더링 하고 내용을 조건부로 렌더링 합니다.
이 예제에서는 Todo 목록을 렌더링 하고 남은 Todo 의 양에 따라 메시지를 표시합니다.
템플릿에서 배열을 순회하려면 {#each}…{/each}
블록을 사용합니다.
HTML을 조건부로 렌더링 하려면 {#if}…{/if}
블록을 사용합니다.
더 많은 조건을 추가하려면 {:else}
및 {:else if …}
지시문을 사용합니다.
TodoList.svelte
<script>
import Todo from './Todo.svelte';
let todos = [
{ task: "Lawn Mowing", completed: false },
{ task: "Walking the Dog", completed: false },
{ task: "Reading Newspaper", completed: false },
];
</script>
{#each todos as todo}
<Todo {...todo} />
{/each}
{#if todos.length === 0}
<p>모든 일이 끝났어요!</p>
{:else if todos.length === 1}
<p>거의 다 왔어요!</p>
{:else}
<p>계속 하세요!</p>
{/if}
{#each}
내에서도 사용할 수 있습니다.TodoList.svelte
{#each todos as todo, index}
<!-- … -->
{/each}
또한 {#each}
블록에서 키를 지정할 수 있습니다.
키는 각 목록의 고유한 식별자입니다.
목록의 인덱스가 변경될 때 DOM을 올바르게 업데이트하기 위해 키를 설정하는 것이 좋습니다.
TodoList.svelte
{#each users as user (user.id)}
<!-- … -->
{/each}
HTML 엘리먼트 및 Svelte 컴포넌트에 대한 이벤트 리스너를 등록하려면 on: 지시문을 사용합니다.
이 예제에서는 작업이 완료될 때 alert(‘잘 했어요!’)를 호출합니다.
Todo.svelte
<script>
export let task;
export let completed = false;
function handleInput(event) {
if (event.target.checked) {
alert('잘 했어요!');
}
}
</script>
<p>
<input
type="checkbox"
checked={completed}
on:input={handleInput}
>
{task}
</p>
아래 예제는 Svelte에 내장된 createEventDispatcher 헬퍼 유틸을 사용하여 부모 컴포넌트에 이벤트를 디스패치할 수 있는 예제입니다.
디스패치할 이벤트 이름과 관련 데이터를 제공하면 됩니다.
Todo.svelte
<script>
import { createEventDispatcher } from 'svelte';
const dispatch = createEventDispatcher();
export let task;
export let completed = false;
function handleInput(event) {
dispatch('checked', {
checked: event.target.checked,
});
}
</script>
<p>
<input
type="checkbox"
checked={completed}
on:input={handleInput}
>
{task}
</p>
TodoList.svelte
<script>
import Todo from './Todo.svelte';
function handleChecked(event) {
if (event.detail.checked) {
alert('잘 했어요!');
}
}
</script>
<Todo
task="잔디 깎기"
on:checked={handleChecked}
/>
<script>
function clear() {
// …
}
</script>
<button on:click|preventDefault={clear}>
할 일 목록 지우기
</button>
Svelte에서는 let 변수를 사용하여 로컬 컴포넌트의 state를 다룹니다.
아래 예제에서는 새로운 Todo를 추가하는 AddTodo 컴포넌트를 만들겠습니다.
데이터는 리액티브하며 state로 사용될 수 있습니다.
Svelte에서는 변수가 재할당되면 해당 컴포넌트가 무효화되고 업데이트가 트리거 됩니다.
업데이트가 트리거 된 후 Svelte는 새로운 state를 반영하기 위해 DOM을 업데이트합니다.
AddTodo.svelte
<script>
import { createEventDispatcher } from 'svelte';
const dispatch = createEventDispatcher();
let task = '';
function handleInput(event) {
task = event.target.value;
}
function submit() {
dispatch('add', {
task,
completed: false,
});
}
</script>
<p>
<input
type="text"
value={task}
on:input={handleInput}
>
<button on:click={submit}>
추가
</button>
</p>
TodoList.svelte
<script>
import Todo from './Todo.svelte';
import AddTodo from './AddTodo.svelte';
let todos = [];
function addTodo(event) {
todos = todos.concat([event.detail]);
}
</script>
{#each todos as todo}
<Todo {...todo} />
{/each}
<AddTodo on:add={addTodo} />
CreateTodo.svelte
<script>
let task = '';
</script>
<input type="text" bind:value={task}>
function addTodo(task) {
todos = todos.concat([{ task, completed: false }]);
}
function addTodo(task) {
todos = [...todos, { task, completed: false }];
}
function addTodo(task) {
todos.push({ task, completed: false });
todos = todos;
}
function addTodo(task) {
// Does not work!
todos.push({ task, completed: false });
}
function completeTodo() {
task = { ...task, completed: true };
}
function completeTodo() {
task.completed = true;
task = task;
}
function completeTodo() {
// Does not work!
task.completed = true;
}
리액티브 statement는 변경되면 계산된 데이터를 파생하거나 다른 작업을 수행하는 데 사용될 수 있습니다.
$:
레이블로 시작하는 문장은 리액티브 문장에 사용된 데이터가 업데이트될 때마다 다시 계산됩니다.
// TodoList.svelte
<script>
import Todo from './Todo.svelte';
import AddTodo from './AddTodo.svelte';
let todos = [];
let showCompleted = false;
$: visibleTodos = showCompleted
? todos
: todos.filter((todo) => todo.completed);
function addTodo(task) {
todos = todos.concat([{
task,
completed: false,
}]);
}
</script>
{#each visibleTodos as todo}
<Todo {...todo} />
{/each}
{#if showCompletedTodos}
<button on:click={() => showCompleted = false}>
완료된 항목 숨기기
</button>
{:else}
<button on:click={() => showCompleted = true}>
완료된 항목 보이기
</button>
{/if}
let todos = [];
$: console.log(todos);
let todos = [];
let showCompleted = false;
$: if (showCompleted) {
console.log(todos);
}
let todos = window.localStorage
? JSON.parse(window.localStorage.getItem('todos') || '[]')
: [];
$: {
console.log(todos);
if (window.localStorage) {
window.localStorage.setItem(
'todos',
JSON.stringify(todos),
);
}
}
스타일은 Svelte 컴포넌트에서 <style>
태그 내에 추가할 수 있습니다.
<!-- Todo.svelte -->
<script>
export let task;
</script>
<p>{task}</p>
<style>
p {
color: red;
}
</style>
아래 예제에서 스타일은 현재 컴포넌트에 대해 범위(scope)가 지정되어 있기 때문에 Todo 내의 p에 영향을 미치지 않습니다.
컴포넌트 외부의 요소에 영향을 주는 전역 스타일을 추가하려면 선택자를 :global로 감싸면 됩니다.
<!-- TodoList.svelte -->
<script>
import Todo from './Todo.svelte';
</script>
<Todo task="Mow lawn" />
<style>
p {
color: green;
}
:global(input[type="checkbox"]) {
accent-color: green;
}
</style>
Svelte 컴포넌트는 CSS 사용자 정의 속성(또는 CSS 변수로도 알려져 있음)도 지원합니다.
아래 예제에서는 HelloWorld 컴포넌트의 색상을 CSS 변수로 재정의할 수 있게 합니다.
‘–color’ 사용자 정의 속성을 빨간색 대체 값과 함께 설정합니다.
<!-- Todo.svelte -->
<script>
export let task;
</script>
<p>{task}</p>
<style>
p {
color: var(--color, red);
}
</style>
Svelte는 CSS 사용자 정의 속성을 컴포넌트 “props"로 지원합니다.
<!-- App.svelte (or your main component) -->
<script>
import Todo from './Todo.svelte';
</script>
<Todo --color="green" />
Svelte는 동적 스타일링을 쉽게 만들기 위해 class: 및 style: 디렉티브를 지원합니다.
아래 예제에서는 HelloWorld에 대한 class 및 style 디렉티브를 시연하겠습니다.
<!-- Todo.svelte -->
<script>
export let task;
export let completed = false;
</script>
<p class:is-completed={completed}>
{task}
</p>
<style>
.is-completed {
text-decoration: line-through;
}
</style>
style:<property>=
방식으로도 스타일을 지정할 수 있습니다.<script>
export let task;
export let completed = false;
</script>
<p style:text-decoration={completed ? 'line-through' : null}>
{task}
</p>