bind:value를 통해서 값을 바인드 한다.
<script>
let name = '';
</script>
<input bind:value={name} placeholder="enter your name" />
<p>Hello {name || 'stranger'}!</p>
<script>
let a = 1;
let b = 2;
</script>
<label>
<input type="number" bind:value={a} min="0" max="10" />
<input type="range" bind:value={a} min="0" max="10" />
</label>
<label>
<input type="number" bind:value={b} min="0" max="10" />
<input type="range" bind:value={b} min="0" max="10" />
</label>
<p>{a} + {b} = {a + b}</p>
bind:checked를 통해서 값을 바인드한다.
예제에서는 yes에 true, false가 저장되어 참조된다.
<script>
let yes = false;
</script>
<label>
<input type="checkbox" bind:checked={yes} />
Yes! Send me regular email spam
</label>
{#if yes}
<p>Thank you. We will bombard your inbox and sell your personal details.</p>
{:else}
<p>You must opt-in to continue. If you're not paying, you're the product.</p>
{/if}
<button disabled={!yes}> Subscribe </button>
bind:group을 통해 관리한다.
group에는 arr같이 해당 그룹들은 담는 객체나 배열이 들어오고, value에는 해당 그룹에 넣을 값을 넣는다.
slice(0, -1)을 사용해 마지막 맛을 제외한 모든 맛들을 , 로 구분하여 나열한다.flavours[flavours.length - 1]로 가져오며, 그 앞에 "and"를 붙여 자연스러운 문장을 만든다.<script>
let scoops = 1;
let flavours = ['Mint choc chip'];
let menu = ['Cookies and cream', 'Mint choc chip', 'Raspberry ripple'];
function join(flavours) {
if (flavours.length === 1) return flavours[0];
return `${flavours.slice(0, -1).join(', ')} and ${flavours[flavours.length - 1]}`;
}
</script>
<h2>Size</h2>
<label>
<input type="radio" bind:group={scoops} value={1} />
One scoop
</label>
<label>
<input type="radio" bind:group={scoops} value={2} />
Two scoops
</label>
<label>
<input type="radio" bind:group={scoops} value={3} />
Three scoops
</label>
<h2>Flavours</h2>
{#each menu as flavour}
<label>
<input type="checkbox" bind:group={flavours} value={flavour} />
{flavour}
</label>
{/each}
{#if flavours.length === 0}
<p>Please select at least one flavour</p>
{:else if flavours.length > scoops}
<p>Can't order more flavours than scoops!</p>
{:else}
<p>
You ordered {scoops}
{scoops === 1 ? 'scoop' : 'scoops'}
of {join(flavours)}
</p>
{/if}
{@html marked}를 통해 마크다운 언어 넣기 가능.
<script>
import { marked } from 'marked';
let text = `Some words are *italic*, some are **bold**`;
</script>
<textarea bind:value={text} />
{@html marked(text)}
<style>
textarea {
width: 100%;
height: 200px;
}
</style>
<script>
let files;
$: if (files) {
// Note that `files` is of type `FileList`, not an Array:
// https://developer.mozilla.org/en-US/docs/Web/API/FileList
console.log(files);
for (const file of files) {
console.log(`${file.name}: ${file.size} bytes`);
}
}
</script>
<label for="avatar">Upload a picture:</label>
<input accept="image/png, image/jpeg" bind:files id="avatar" name="avatar" type="file" />
<label for="many">Upload multiple files of any type:</label>
<input bind:files id="many" multiple type="file" />
{#if files}
<h2>Selected files:</h2>
{#each Array.from(files) as file}
<p>{file.name} ({file.size} bytes)</p>
{/each}
{/if}
input bind:value={answer}를 통해 answer값을 바인딩함.<script>
let questions = [
{ id: 1, text: `Where did you go to school?` },
{ id: 2, text: `What is your mother's name?` },
{ id: 3, text: `What is another personal fact that an attacker could easily find with Google?` }
];
let selected;
let answer = '';
function handleSubmit() {
alert(`answered question ${selected.id} (${selected.text}) with "${answer}"`);
}
</script>
<h2>Insecurity questions</h2>
<form on:submit|preventDefault={handleSubmit}>
<select bind:value={selected} on:change={() => (answer = '')}>
{#each questions as question}
<option value={question}>
{question.text}
</option>
{/each}
</select>
<input bind:value={answer} />
<button disabled={!answer} type="submit"> Submit </button>
</form>
<p>selected question {selected ? selected.id : '[waiting...]'}</p>
<style>
input {
display: block;
width: 500px;
max-width: 100%;
}
</style>
<script>
let scoops = 1;
let flavours = ['Mint choc chip'];
let menu = ['Cookies and cream', 'Mint choc chip', 'Raspberry ripple'];
function join(flavours) {
if (flavours.length === 1) return flavours[0];
return `${flavours.slice(0, -1).join(', ')} and ${flavours[flavours.length - 1]}`;
}
</script>
<h2>Size</h2>
<label>
<input type="radio" bind:group={scoops} value={1} />
One scoop
</label>
<label>
<input type="radio" bind:group={scoops} value={2} />
Two scoops
</label>
<label>
<input type="radio" bind:group={scoops} value={3} />
Three scoops
</label>
<h2>Flavours</h2>
<select multiple bind:value={flavours}>
{#each menu as flavour}
<option value={flavour}>
{flavour}
</option>
{/each}
</select>
{#if flavours.length === 0}
<p>Please select at least one flavour</p>
{:else if flavours.length > scoops}
<p>Can't order more flavours than scoops!</p>
{:else}
<p>
You ordered {scoops}
{scoops === 1 ? 'scoop' : 'scoops'}
of {join(flavours)}
</p>
{/if}
<script>
let todos = [
{ done: false, text: 'finish Svelte tutorial' },
{ done: false, text: 'build an app' },
{ done: false, text: 'world domination' }
];
function add() {
todos = todos.concat({ done: false, text: '' });
}
function clear() {
todos = todos.filter((t) => !t.done);
}
$: remaining = todos.filter((t) => !t.done).length;
</script>
<h1>Todos</h1>
{#each todos as todo}
<div>
<input type="checkbox" bind:checked={todo.done} />
<input placeholder="What needs to be done?" bind:value={todo.text} disabled={todo.done} />
</div>
{/each}
<p>{remaining} remaining</p>
<button on:click={add}> Add new </button>
<button on:click={clear}> Clear completed </button>
<script>
// These values are bound to properties of the video
let time = 0;
let duration;
let paused = true;
let showControls = true;
let showControlsTimeout;
// Used to track time of last mouse down event
let lastMouseDown;
function handleMove(e) {
// Make the controls visible, but fade out after
// 2.5 seconds of inactivity
clearTimeout(showControlsTimeout);
showControlsTimeout = setTimeout(() => (showControls = false), 2500);
showControls = true;
if (!duration) return; // video not loaded yet
if (e.type !== 'touchmove' && !(e.buttons & 1)) return; // mouse not down
const clientX = e.type === 'touchmove' ? e.touches[0].clientX : e.clientX;
const { left, right } = this.getBoundingClientRect();
time = (duration * (clientX - left)) / (right - left);
}
// we can't rely on the built-in click event, because it fires
// after a drag — we have to listen for clicks ourselves
function handleMousedown(e) {
lastMouseDown = new Date();
}
function handleMouseup(e) {
if (new Date() - lastMouseDown < 300) {
if (paused) e.target.play();
else e.target.pause();
}
}
function format(seconds) {
if (isNaN(seconds)) return '...';
const minutes = Math.floor(seconds / 60);
seconds = Math.floor(seconds % 60);
if (seconds < 10) seconds = '0' + seconds;
return `${minutes}:${seconds}`;
}
</script>
<h1>Caminandes: Llamigos</h1>
<p>From <a href="https://studio.blender.org/films">Blender Studio</a>. CC-BY</p>
<div>
<video
poster="https://sveltejs.github.io/assets/caminandes-llamigos.jpg"
src="https://sveltejs.github.io/assets/caminandes-llamigos.mp4"
on:mousemove={handleMove}
on:touchmove|preventDefault={handleMove}
on:mousedown={handleMousedown}
on:mouseup={handleMouseup}
bind:currentTime={time}
bind:duration
bind:paused
>
<track kind="captions" />
</video>
<div class="controls" style="opacity: {duration && showControls ? 1 : 0}">
<progress value={time / duration || 0} />
<div class="info">
<span class="time">{format(time)}</span>
<span>click anywhere to {paused ? 'play' : 'pause'} / drag to seek</span>
<span class="time">{format(duration)}</span>
</div>
</div>
</div>
<style>
div {
position: relative;
}
.controls {
position: absolute;
top: 0;
width: 100%;
transition: opacity 1s;
}
.info {
display: flex;
width: 100%;
justify-content: space-between;
}
span {
padding: 0.2em 0.5em;
color: white;
text-shadow: 0 0 8px black;
font-size: 1.4em;
opacity: 0.7;
}
.time {
width: 3em;
}
.time:last-child {
text-align: right;
}
progress {
display: block;
width: 100%;
height: 10px;
-webkit-appearance: none;
appearance: none;
}
progress::-webkit-progress-bar {
background-color: rgba(0, 0, 0, 0.2);
}
progress::-webkit-progress-value {
background-color: rgba(255, 255, 255, 0.6);
}
video {
width: 100%;
}
</style>
<script>
let w;
let h;
let size = 42;
let text = 'edit me';
</script>
<input type="range" bind:value={size} />
<input bind:value={text} />
<p>size: {w}px x {h}px</p>
<div bind:clientWidth={w} bind:clientHeight={h}>
<span style="font-size: {size}px">{text}</span>
</div>
<style>
input {
display: block;
}
div {
display: inline-block;
}
</style>
<script>
import { onMount } from 'svelte';
let canvas;
onMount(() => {
const ctx = canvas.getContext('2d');
let frame;
(function loop() {
frame = requestAnimationFrame(loop);
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
for (let p = 0; p < imageData.data.length; p += 4) {
const i = p / 4;
const x = i % canvas.width;
const y = (i / canvas.height) >>> 0;
const t = window.performance.now();
const r = 64 + (128 * x) / canvas.width + 64 * Math.sin(t / 1000);
const g = 64 + (128 * y) / canvas.height + 64 * Math.cos(t / 1400);
const b = 128;
imageData.data[p + 0] = r;
imageData.data[p + 1] = g;
imageData.data[p + 2] = b;
imageData.data[p + 3] = 255;
}
ctx.putImageData(imageData, 0, 0);
})();
return () => {
cancelAnimationFrame(frame);
};
});
</script>
<canvas bind:this={canvas} width={32} height={32} />
<style>
canvas {
width: 100%;
height: 100%;
background-color: #666;
-webkit-mask: url(/svelte-logo-mask.svg) 50% 50% no-repeat;
mask: url(/svelte-logo-mask.svg) 50% 50% no-repeat;
}
</style>
<script>
import Keypad from './Keypad.svelte';
let pin;
$: view = pin ? pin.replace(/\d(?!$)/g, '•') : 'enter your pin';
function handleSubmit() {
alert(`submitted ${pin}`);
}
</script>
<h1 class:pin>{view}</h1>
<Keypad bind:value={pin} on:submit={handleSubmit} />
<style>
h1 {
color: #ccc;
}
h1.pin {
color: #333;
}
:global(body.dark) h1 {
color: #444;
}
:global(body.dark) h1.pin {
color: #fff;
}
</style>