Svelte 초보자용 블러셔.

90674 단어 JavaScriptSveltetech

개요

  • 자기용으로만 정리
  • 기본적으로 공식 문서의 강좌에서 발췌
  • 평소에 Vue를 쓰는데 Svelte는 문외한 상태에서 제작된 것으로 내용에 오류가 있을 수 있음
  • Type Script, Svelte Kit 제외
  • 개발 환경 구축


    이 가능하다, ~할 수 있다,...
    yarn create vite my-svelte-app --template svelte
    cd my-svelte-app/
    yarn install
    yarn dev
    
    localhost:3000에서 이동했습니다.
    vscode라면 Svelte용 확장을 추가하면 문법 하이라이트와 코드 기호가 작용합니다
    https://marketplace.visualstudio.com/items?itemName=svelte.svelte-vscode

    어셈블리의 기본 구조


    Vue와 유사한 SFC는 파일.svelte에 스크립트, 템플릿 및 스타일을 설명합니다.
    <script>
      const name = 'Svelte'
    </script>
    
    <main>
      <h1>Hello, {name}</h1>
    </main>
    
    <style>
      h1 {
        color: gray;
      }
    </style>
    

    요소 속성에 바인딩

    {}를 통해 데이터 바인딩 가능
    <script>
      const src = "https://storage.googleapis.com/zenn-user-upload/avatar/845fa75ba8.jpeg"
    </script>
    
    <main>
      <img src={src}>
    </main>
    
    속성 이름과 연결된 변수 이름이 일치할 때 생략 가능
    <main>
      <img {src}>
    </main>
    

    스타일링


    스타일 블록에 설명된 CSS는 기본적으로 구성 요소 로컬이며 태그 선택기를 사용해도 다른 구성 요소를 방해하지 않습니다.
    <p>This is a paragraph.</p>
    
    <style>
      p {
        color: purple;
        font-family: "Comic Sans MS", cursive;
        font-size: 2em;
      }
    </style>
    

    외부 구성 요소 활용


    import만 기입하면 즉시 사용 가능
    <script>
      import Child from "./components/Child.svelte";
    </script>
    
    <Child />
    

    텍스트 출력을 들여쓰지 않음


    XSS 조심하세요.
    <script>
      const html = '<h1>Hello, World!</h1>'
    </script>
    
    <div>{@html html}</div>
    

    DOM 이벤트 처리


    <script>
      let count = 0
      function increment() {
        count += 1
      }
    </script>
    
    <button on:click={increment}>
      {count}
    </button>
    
    내연도 가능
    <div on:mousemove={e => m = { x: e.clientX, y: e.clientY }}>
    	The mouse position is {m.x} x {m.y}
    </div>
    
    모뎀(once, prevent Default, stop Proopagation 등)은 |에서 설정할 수 있습니다.
    <button on:click|once|capture={handleClick}>
    	Click me
    </button>
    

    Reactive Declarations


    일본어로 뭐라고 부르는지는 몰라도 뷰의 컴퓨터 같은 거
    let count = 0
    $: doubled = count * 2
    
    블록을 확장해도 여러 줄을 쓸 수 있습니다.
    $: {
      console.log('count changed!!')
      console.log(`the count is ${count}`)
    }
    
    이렇게 하면 조건식도 쓸 수 있어요.
    $: if (count > 10) {
      alert('count is over 10')
    }
    

    배열이나 객체를 업데이트하는 방법


    태그 또는 Tips이지만 Vue(v2)와 마찬가지로 객체 배열 작업에 재활동이 반영되지 않는 경우가 있습니다.Array#push시 재활성화 불가
    <script>
      let array = [1,2,3]
      function push() {
        array.push(array[array.length - 1] + 1) // ← NG
      }
    </script>
    
    <button on:click={push}>
      {array.join(',')}
    </button>
    
    Svelte라면 대입은 다시 활성화되는 트리거가 되므로 대입을 명확히 하면 OK
    <script>
      let array = [1,2,3]
      function push() {
        array = [...array, array[array.length - 1] + 1] // ← OK
      }
    </script>
    
    <button on:click={push}>
      {array.join(',')}
    </button>
    

    구성 요소의 props 정의


    export 변수만 통해proops로 모듈에서 주입할 수 있습니다
    Child.svelte
    <script>
      export let value
    </script>
    
    <p>props value is {value}</p>
    
    Parent.svelte
    <Child value=1 />
    
    물론props에 귀속할 수 있습니다
    Parent.svelte
    <Child value={count} />
    
    props 옆에 초기값이 첨부되어 있으면 기본값이 됩니다
    Child.svelte
    export let value = 1
    
    여러 개의 프로포즈가 있는 경우 대상을 통일적으로 지정할 수 있다
    Child.svelte
    export let a
    export let b
    export let c
    
    Parent.svelte
    <script>
      import Child from './components/Child.svelte'
      const props = {
        a: 1,
        b: 2,
        c: 3
      }
    </script>
    
    <Child {...props} />
    

    템플릿의 조건 브랜치


    Vue의 v-if 같은 거.
    {#if value % 3 === 0 && value % 5 === 0}
      <div>FizzBuzz</div>
    {:else if value % 3 === 0}
      <div>Fizz</div>
    {:else if value % 5 === 0}
      <div>Buzz</div>
    {:else}
      <div>{value}</div>
    {/if}
    

    템플릿 사이클


    Vue의 v-for 같은 거.
    {#each values as value}
      <p>{value}</p>
    {/each}
    

    템플릿의 Promise 상태의 분기


    Promise 변수의 상태에 따라 템플릿으로 분기할 수 있기 때문에 외부 데이터를 읽을 때 메시지 등을 표시할 수 있습니다
    <script>
      const promise = new Promise((resolve, reject) => {
        setTimeout(() => {
          resolve('resolved');
        }, 1000);
      });
    </script>
    
    {#await promise}
      <p>...waiting</p>
    {:then value}
      <p>{value}</p>
    {:catch error}
      <p>{error.message}</p>
    {/await}
    

    구성 요소에서 이벤트 점화


    베일에 가까운 에잇 녀석
    Child.svelte
    <script>
      import { createEventDispatcher } from 'svelte'
      const dispatch = createEventDispatcher()
      const message = 'Child Value'
    
      function sayHello() {
        dispatch('sayHello', { message })
      }
    </script>
    
    <button on:click={sayHello}>clickMe</button>
    
    Parent.svelte
    <script>
      import Child from './components/Child.svelte'
    </script>
    
    <Child on:sayHello={e => console.log(e.detail.message)}/>
    
    사용자 정의 이벤트가 아닌 DOM 이벤트를 부모에게 직접 전파하는 경우 생략 기법을 사용할 수 있습니다
    <button on:click>ClickMe</button>
    

    창 요소에 귀속


    input
    <input bind:value={name}>
    
    input[type=number] input[type=range]의 경우 은근히 수치로 변환
    <input type=number bind:value={a} min=0 max=10>
    <input type=range bind:value={a} min=0 max=10>
    
    Checkbox
    <input type=checkbox bind:checked={yes}>
    
    Textarea
    <textarea bind:value={value}></textarea>
    
    Select
    <select bind:value={selectedValue} on:change="{() => answer = ''}">
    
    Select(multiple)
    <select multiple bind:value={flavours}>
    
    라디오(그룹)
    둘 중 하나를 선택한 상태로 여러 라디오를 그룹화합니다.
    <label>
      <input type=checkbox bind:group={selectedValues} name="option" value="one">
      One
    </label>
    
    <label>
      <input type=checkbox bind:group={selectedValues} name="option" value="two">
      Two
    </label>
    
    <label>
      <input type=checkbox bind:group={selectedValues} name="option" value="three">
      Three
    </label>
    
    체크박스(그룹)
    여러 개의 체크 상자를 조합하여, 그룹으로 각 체크 상자의 상태를 감시한다
    <label>
      <input
        type="checkbox"
        bind:group={selectedValues}
        name="option"
        value="one"
      />
      One
    </label>
    
    <label>
      <input
        type="checkbox"
        bind:group={selectedValues}
        name="option"
        value="two"
      />
      Two
    </label>
    
    <label>
      <input
        type="checkbox"
        bind:group={selectedValues}
        name="option"
        value="three"
      />
      Three
    </label>
    

    요소에 특수 바인딩


    Readonly 속성에 바인딩
    DOM의 상태가 변경된 경우 변수에 반영되지만, 변수를 덮어쓰더라도 DOM의 상태는 변경되지 않습니다.
    <div bind:clientWidth={w} bind:clientHeight={h}>Hello</div>
    { w } { h }
    
    DOM에 사용되는 컨텍스트this를 바인딩하여 JavaScript 참조 요소에서 직접 참조
    <canvas
      bind:this={canvas}
      width={32}
      height={32}
    ></canvas>
    

    어셈블리 라이프 사이클


    onMount/onDestroy에 import 필요
    import { onMount, onDestroy } from 'svelte'
    
    onMount(() => console.log('Mounted'))
    onDestroy(() => console.log('Destroyed'))
    
    Vue의nextTick처럼 ticks를 사용하여 다음 모습을 기다립니다
    import { tick } from 'svelte'
    await tick();
    

    귀속


    대체로 Vue와 마찬가지로 상태에 따라 class를 전환할 수 있습니다
    <button
    	class="{current === 'foo' ? 'selected' : ''}"
    	on:click="{() => current = 'foo'}"
    >foo</button>
    
    클래스 이름과 변수 이름이 같을 때 생략 가능
    <div class:big>
    	<!-- ... -->
    </div>
    

    Store


    상점은 관련되지 않은 구성 요소 사이, 모듈 사이에서 상태를 공유하는 메커니즘이다writable에 쓰기 가능한 스토리지 기기 생성 가능
    import { writable } from 'svelte/store'
    export const count = writable(0)
    
    writablesetupdate에서 인터페이스를 사용하는 값을 업데이트할 수 있습니다.
    function increment() {
      count.update(n => n + 1)
    }
    
    function reset() {
      count.set(0)
    }
    
    writable 인터페이스는 subscribe 방법으로 값의 변화를 감시할 수 있다.subscribe 방법은 unsubscribe에 사용된 방법으로 되돌아오는 값으로 적당히 unsubscribe 메모리 유출을 피하는 것이다
    const unsubscribe = count.subscribe(value => localValue = value)
    onDestroy(() => unsubscribe())
    
    온라인 쇼핑몰의 구독과 라이프 사이클 관리가 까다로워 바로 가기를 준비했다.$ 머리 위에 놓고 참고하면subscrie/unsubscribe를 마음대로 할 수 있습니다.
    $count
    
    읽기 전용 스토리지를 readable에 생성readable 초기값을 첫 번째 인자로 설정하고 첫 번째subscribe에서 실행된 호출 함수를 두 번째 인자로 설정합니다.이 시간set에만 값을 설정할 수 있습니다.
    또한 구독자가 0일 때의 후처리를 호출 함수의 반환값으로 설명할 수 있다
    import { readable } from 'svelte/store'
    
    const time = readable(new Date(), (set) => {
      const interval = setInterval(() => {
        set(new Date())
      }, 1000)
    
      return () => clearInterval(interval)
    })
    
    derived에서 다른 상점의 값에 의존하는 상점을 만들 수 있다.상점 같은 거computed죠.
    const count = writable(0)
    const doubleCount = derived(count, $count => $count * 2)
    
    subscribe는 대상에 방법만 포함되면 메모리로 작용하기 때문에 setupdate를 숨길 수 있다.
    import { writable } from "svelte/store";
    
    function createCount() {
      const { subscribe, set, update } = writable(0);
    
      return {
        subscribe,
        increment: () => update((n) => n + 1),
        decrement: () => update((n) => n - 1),
        reset: () => set(0),
      };
    }
    
    export const count = createCount();
    

    Motion

    tweened 부드러운 값 업데이트를 하는 대상을 생성하여 저장과 같은 방식subscribeset 방법으로 업데이트와 구독을 진행한다.
    import { tweened } from 'svelte/motion'
    
    const progress = tweened(0)
    progress.subscribe(value => console.log(value))
    progress.set(100)
    
    단순히 0에서 100으로 업데이트하는 것이 아니라 업데이트 작업을 반복하며 조금씩 0에서 100에 가까워진다.springtweened이지만 업데이트가 잦은 경우
    import { spring } from 'svelte/motion'
    
    const progress = spring(0)
    progress.subscribe(value => console.log(value))
    progress.set(100)
    

    Transitions


    요소를 표시하거나 숨길 때 애니메이션을 쉽게 설정할 수 있습니다.
    <script>
      import { fade } from 'svelte/transition'
      let isShow = false
    </script>
    
    <label>
      <input type="checkbox" bind:checked={isShow}>
      show
    </label>
    
    {#if isShow}
      <p transition:fade>トランジションサンプル</p>
    {/if}
    
    import의transition 함수에 따라 서로 다른 점프를 표시할 수 있는 것 외에 추가 파라미터를 통해 미세하게 조정할 수 있다
    {#if isShow}
      <p transition:fly="{{ y: 200, duration: 2000 }}">トランジションサンプル</p>
    {/if}
    
    표시하고 숨길 때도 다른 점프를 설정할 수 있습니다
    <p in:fly="{{ y: 200, duration: 2000 }}" out:fade>トランジションサンプル</p>
    
    연결 점프당 라이프 사이클
    <p
      transition:fade
      on:introstart={() => console.log("introstart")}
      on:outrostart={() => console.log("outrostart")}
      on:introend={() => console.log("introend")}
      on:outroend={() => console.log("outroend")}
    >
      トランジションサンプル
    </p>
    
    컴포넌트를 업데이트할 때마다 점프를 다시 실행하려는 경우{#key} 블록 사용
    {#key value}
      <div transition:fade>{value}</div>
    {/key}
    

    Actions


    동작은 요소 단위의 생명 주기를 정의할 수 있다.
    actions/outerClickable
    export function outerClickable(node) {
      const handleClick = (event) => {
        if (!node.contains(event.target)) {
          node.dispatchEvent(new CustomEvent("outclick"));
        }
      };
    
      document.addEventListener("click", handleClick, true);
    
      return {
        destroy() {
          document.removeEventListener("click", handleClick, true);
        },
      };
    }
    
    요소를 생성하는 시간과 버리는 시간을 정의할 수 있기 때문에 DOM 이벤트의 안전 관리에 사용할 수 있습니다.
    App.svelte
    <script>
      import { outerClickable } from './actions/outerClickable'
    </script>
    
    <div use:outerClickable on:outclick={() => alert('outclick!')}>要素の外側をクリックするとアラートが鳴るよ</div>
    
    동작도 매개변수를 지정할 수 있습니다.
    actions/longpress.js
    export function longpress(node, duration) {
    }
    
    App.svelte
    <button use:longpress={duration}>Push</button>
    

    Slot


    기본적으로 Vue 또는 웹 Components와 함께 제공
    <div class="box">
      <slot></slot>
    </div>
    
    슬로트에 어떤 것도 주입하지 않은 2배의 회력을 지정합니다
    <div class="box">
      <slot>
        <em>no content was provided</em>
      </slot>
    </div>
    
    명명조
    ContentCard.svelte
    <article class="contact-card">
      <h2>
        <slot name="name">
          <span class="missing">Unknown name</span>
        </slot>
      </h2>
    
      <div class="address">
        <slot name="address">
          <span class="missing">Unknown address</span>
        </slot>
      </div>
    
      <div class="email">
        <slot name="email">
          <span class="missing">Unknown email</span>
        </slot>
      </div>
    </article>
    
    App.svelte
    <ContactCard>
      <span slot="name"> P. Sherman </span>
    
      <span slot="address">
        42 Wallaby Way<br />
        Sydney
      </span>
    </ContactCard>
    
    주입된 슬롯 액세스
    {#if $$slots.comments}
    	<div class="discussion">
    		<h3>Comments</h3>
    		<slot name="comments"></slot>
    	</div>
    {/if}
    
    슬롯에 속성 주입
    Child.svelte
    <div>
    	<slot value={localValue}></slot>
    </div>
    
    Parent.svelte
    <Child let:value>
      { value }
    </Child>
    

    Context API


    React의 Context와 대체로 같다
    const key = Symbol();
    
    setContext(key, {
      getValue: () => value,
    });
    
    const { getValue } = getContext(key)
    

    Special elements


    반복 그리기
    <svelte:self>
    
    동적으로 그릴 구성 요소 결정
    <svelte:component this={selected.component}/>
    
    윈도 대상을 연결할 수 있는 이벤트 청중의 추상적인 구성 요소
    <svelte:window bind:scrollY={y} on:keydown={handleKeydown}/>
    
    역시 바디.
    <svelte:body
      on:mouseenter={handleMouseenter}
      on:mouseleave={handleMouseleave}
    />
    
    헤더에 라벨 주입
    <svelte:head>
      <link rel="stylesheet" href="/tutorial/dark-theme.css">
    </svelte:head>
    
    여러 요소를 조합한 추상적 요소
    <Box>
      <svelte:fragment slot="footer">
        <p>All rights reserved.</p>
        <p>Copyright (c) 2019 Svelte Industries</p>
      </svelte:fragment>
    </Box>
    

    Module context


    여러 개의 같은 구성 요소를 사용할 때, 구성 요소 사이에는 공통된 작용이 있다.privte static 같은...?
    <script context="module">
      let current;
    </script>
    
    <script context="module">
      const elements = new Set();
    
      export function stopAll() {
        elements.forEach(element => {
          element.pause();
        });
      }
    </script>
    

    Debugging


    렌더링 시 로그 출력 가능
    {@debug user}
    

    좋은 웹페이지 즐겨찾기