ทำเว็บ todo list แบบง่ายๆ โดยใช้ Svelte และ Tailwind CSS เป็นครั้งแรก

Programming May 6, 2022

และแล้วก็ถึงเวลา... ทำบล็อกเกี่ยวกับ Svelte ซะที หลังจากที่ชาวคณะเริ่มทำกันเว็บที่ใช้ Svelte กันไปนานแล้วหล่ะ

บล็อกนี้เรามาลองทำเว็บไซต์ todo list โดยใช้ Svelte และ Tailwind CSS ซึ่งอ้างอิงจากพี่นาตร จากใน session ของงาน Barcamp Bangkok 2022

เราจะค่อยๆไปพร้อมๆกันเนอะ


Svelte 101

อ้างอิงจาก session พี่หนุ่มที่พูดในงาน Barcamp Bangkok 2022 นะ ซึ่งคลิปย้อนหลังไม่รู้จะมาเมื่อไหร่

Svelte (อ่านว่า สะ-เว่ล-ทึ) เป็น compiler คือ มีการทำ code compile เพื่อให้คอมเข้าใจง่ายขึ้น (เหมือนฝั่ง blockchain ที่มันไม่เข้าใจภาษา solidity เลยต้อง compile ให้มันอ่านรู้เรื่องอ่ะ ประมาณนี้เลย)

Svelte จะเขียนโค้ดที่อัปเดต DOM เมื่อสถานะของแอปเปลี่ยนแปลง ซึ่งเพิ่มมาบูมตอนเป็น Svelte 3 นะ ด้วย Rethinking reactivity

Svelte 3: Rethinking reactivity
It’s finally here

หลักการของ Svelte ไปดูคลิปนี้ได้เลยยย

document ของ Svelte สามารถเข้าไปอ่านได้ที่

Svelte
Cybernetically enhanced web apps

และเข้าไปส่อง quickstart guide เพื่อเริ่มทำได้เลย โดยการ run command เพื่อ clone มันออกมาแล้ว run ได้เลย หรือใช้ vite เพื่อทำ hot reload ให้ ก็ได้เช่นกัน

ข้อดีของ Svelte คือทำให้ developer ออกของได้เร็วขึ้น พี่หนุ่มเลยใช้เวลาทำ thwordle 2 วัน แล้วก็อันนี้ ชิง Keychron ใช้เวลาทำชั่วโมงเดียวเสร็จ

Svelte vs Svelte Kit

ทำความรู้จักกับ Svelte กันไปแล้ว มาทำความรู้จัก Svelte Kit กันต่อเลย

เจ้า Svelte Kit เป็น framework ในการสร้างแอพพลิเคชั่น แล้วก็รองรับเรื่อง Routing ต่างๆด้วยนะ

SvelteKit
The fastest way to build Svelte apps
What’s the deal with SvelteKit?
We’re rethinking how to build Svelte apps. Here’s what you need to know

ถ้าเปรียบเทียบง่ายๆ Svelte จะเหมือน React ส่วน Svelte Kit จะเหมือน Next.js นั่นเอง

เรียนรู้ Svelte โดยการทำ todo list กันเถอะ

เราจะค่อยๆไปกันเนอะ

เตรียมตัวกันก่อน

อันนี้ไม่มีอะไรมาก ก็ทำการ install ของต่างๆลงไป

npm install

โปรเจกต์นี้เราจะใช้ Svelte Kit พร้อมลง Tailwind CSS ตามนี้เลย

GitHub - svelte-add/tailwindcss: Add Tailwind CSS to your Svelte project
Add Tailwind CSS to your Svelte project. Contribute to svelte-add/tailwindcss development by creating an account on GitHub.

อันนี้การลง Tailwind CSS สำหรับ Svelte เฉยๆ

How to use Tailwind CSS with Svelte - LogRocket Blog
Create beautiful, custom components with Tailwind CSS to style your Svelte app using this step-by-step tutorial.

โค้ดต่างๆสามารถไปส่องในนี้เพื่อ adapt ไปตามที่เราต้องการได้ เย้ๆ

Svelte examples
Cybernetically enhanced web apps

คิดว่าหลายๆคนคงจะใช้ VS Code กัน แนะนำให้ติด plug-in ของ Svelte ก่อนจ้า

ไฟล์ที่เราไปทำกัน ถ้าเป็น Svelte เฉยๆ จะอยู่ใน src/App.svelte และถ้าเป็น Svelte Native เอ้ยยย Svelte Kit ก็จะอยู่ใน src/routes/index.svelte

และถ้าเราจะทำการ run เพื่อ ดูหน้าเว็บ สามารถใช้คำสั่งนี้ได้เลยจ้า

npm run dev

ของ Tailwind CSS มี plug-in ลง VS Code ตามนี้เลย

Editor Setup - Tailwind CSS
Plugins and configuration settings that can improve the developer experience when working with Tailwind CSS.

สร้าง text hello world

เรามารู้จักโครงสร้างในไฟล์ Svelte กันก่อนเลย ถ้าใครเคยเขียน Vue.js มาก่อนก็จะคุ้นๆเนอะ ที่ไฟล์นึงมี html, css, และ javascript ซึ่งเจ้า Svelte ก็เหมือนกันเลยหล่ะนะ

มาดูโค้ดนี้กัน ส่วนบนจะเป็นส่วนของ <script> ประกอบด้วยโค้ด javascript ที่เราเขียนขึ้นมาเพื่อทำงานอะไรบางอย่างก่อนแสดงผล และข้างล่าง ใช่ค่ะ HTML ปกติเลย

<script>
    export let name = "world";
</script>

<h1>Hello {name}!</h1>

การทำงาน คือ เอาค่า name ในที่นี้จะเท่ากับ world เนอะ มาแสดงในหน้าเว็บ ผลที่ได้ก็จะเป็น Hello world! นั่นเอง

ตัวอย่างในเว็บ Svelte

Svelte examples
Cybernetically enhanced web apps
https://svelte.dev/examples/hello-world

เพิ่ม text input

เป็นการเปลี่ยน text ตาม input ที่เราใส่เข้าไป

ในส่วนของ name อันนี้เป็นค่าว่างไว้ และค่าจะเปลี่ยนเมื่อมีการเปลี่ยนค่าใน input (ที่ทาง Android เรียกว่า EditText อ่ะ) จะมีการ bind ค่าไปที่ name และใส่ placeholder ไว้ถ้ามันเป็นค่าว่าง

<script>
    export let name = '';
</script>

<input bind:value={name} placeholder="enter something">
<h1>{name}</h1>

หน้าตาจะประมาณนี้ ขี้เกียจทำรูป gif หล่ะนะ

กดปุ่มเพื่อนำค่าจาก input มาอัพเดต

ในตอนนี้เราจะเพิ่มปุ่ม เพื่อทำการอัพเดตข้อมูล ผ่าน event onClick ด้วย function ที่ชื่อว่า handleClick() โดยนำค่า input จะมาจาก input field มาใส่ในค่า output นั่นเอง

<script>
    export let input;
    export let output = "";

    function handleClick() {
        output = input;
    }
</script>

<input bind:value={input} placeholder="enter something">
<button on:click={handleClick}>
    Add
</button>
<h1>{output}</h1>

ผลที่ได้ก็จะประมาณนี้แหละเนอะ ค่าจะไม่ update แบบ real-time เหมือนมะกี้แล้วนะ

เพิ่ม checkbox เพื่อทำ todo list

ก่อนอื่นเรามาสร้าง array list ตัวนึง เพื่อเก็บ todo list ของเรา ชื่อว่า todoList ก็แล้วกันเนอะ

สมมุติว่าเรามีของอยู่แล้วใน list เราจะแสดงผลยังไงหล่ะ? เราจะต้องใช้ loop นั่นเอง

โดยใน Svelte จะใช้ syntax ประมาณนี้

<script>
    let todoList = ["todo 1", "todo 2", "todo 3"];
</script>

{#each todoList as todo}
    <p>{todo}</p>
{/each}

ปกติเราจะเห็น for item to list กันเนอะ แต่ใน Svelte มันจะสลับกันเนอะ เป็น each list as item

แล้วก็ตัวบล็อก มันจะขึ้นต้นด้วย # แล้วจบด้วย / นะ

Svelte examples
Cybernetically enhanced web apps

ผลที่ได้จ้า

จากนั้นมาเพิ่ม checkbox กันหน่อยจ้า โดยมันจะอยู่หน้า text เนอะ เราจะใช้ div ครอบ แล้วเติม input ที่เป็น type checkbox เข้าไป

<script>
    let todoList = ["todo 1", "todo 2", "todo 3"];
</script>

{#each todoList as todo}
    <div>
        <input type=checkbox>
        <p>{todo}</p>
    </div>
{/each}

พบว่า มันอยู่คนละบรรทัด มันไม่กลางอ่า

แน่นอนว่าการจัดให้มันอยู่แถวเดียวกันนั้น เป็นหน้าที่ของ Tailwind CSS นั่นเอง

เราจะวางเจ้า checkbox และ text เป็น flex เนอะ วางในแถวเดียวกัน

{#each todoList as todo}
    <div class="flex flex-row">
        <input type=checkbox>
        <p>{todo}</p>
    </div>
{/each}
Flex Basis - Tailwind CSS
Utilities for controlling the initial size of flex items.

อ่ะยังไม่สวย งั้นขยับให้เขาห่างกันนิดนึง ให้ text ห่างไปอีกสักนิดนึง

{#each todoList as todo}
    <div class="flex flex-row">
        <input type=checkbox>
        <p class="mx-4">{todo}</p>
    </div>
{/each}

เอ่ออออ ทำไมมันตกๆ

Margin - Tailwind CSS
Utilities for controlling an element’s margin.

งั้นลอง check ดูดีกว่า เหมือน text สูงกว่า checkbox อ่ะ

งั้นขยับ checkbox ให้อยู่ตรงกลางหน่อย

{#each todoList as todo}
    <div class="flex flex-row">
        <input class="place-self-center" type=checkbox>
        <p class="mx-4">{todo}</p>
    </div>
{/each}

อ่ะ สวยงามตามท้องเรื่องหล่ะ

Place Self - Tailwind CSS
Utilities for controlling how an individual item is justified and aligned at the same time.

เมื่อเราแสดงของใน todoList ที่เรา mock มาเรียบร้อยแล้ว ทำการลบไส้ในทิ้ง เหลือแค่ array เปล่า

let todoList = [];

เพราะเราจะทำการอัพเดตค่าที่ได้จาก input เข้าไปใส่ใน todoList นั่นเอง

เราจะสร้าง function ใหม่ ชื่อว่า addTodo เปลี่ยนจากของเดิมที่เป็น handleClick เนอะ

การทำงานของ addTodo ก็ตรงไปตรงมา เอา input ที่ได้จาก input field มาใส่ใน list แล้วเคลียร์ค่า input ที่ได้ออกไป

ในทางปกติ เราจะเพิ่มของใน array list ด้วยท่าประมาณว่า list.add(item) อะไรประมาณนี้ หรือถ้าเขียนเป็น javascript จะเป็น todoList.push(input) แต่ใน Svelte ไม่สามารถทำท่านี้ได้นะ มันจะไม่ render ให้

ดังนั้นจะใช้ท่า x =... เพื่อให้เจ้า Svelte รู้ว่า เฮ้ยย ค่านี้เกิดการเปลี่ยนแปลงอ่ะ เป็นการ spread ตัวเองออกมา แล้วเพิ่มของใหม่เข้าไป แล้ว reassign ค่าอีกหนึ่งรอบ

หน้าตาจะเป็นแบบนี้

todoList = [...todoList, input];

หน้าตาโค้ดทั้งหมดในตอนนี้

<script>
    export let input = "";

    let todoList = [];

    function addTodo() {
        todoList = [...todoList, input];
        console.log(todoList);
        input = '';
    }
</script>

<h1>TODO LIST</h1>

<input bind:value={input} placeholder="enter something">
<button on:click={addTodo}>
    Add
</button>

{#each todoList as todo}
    <div>
        <input type=checkbox>
        <p>{todo}</p>
    </div>
{/each}

ผลที่ได้จ้า

กด checkbox สักหน่อย

ถือว่าใช้งานได้หล่ะ จบบล็อกเพียงเท่านี้ เดี๋ยวสิๆๆ กด checkbox แล้วต้องขีดฆ่าทิ้งด้วยสิ ว่าเราทำอันนี้ไปแล้วนะ

กด checkbox เพื่อขีดฆ่า

เมื่อเรากด checkbox ที่ item แล้ว ให้ทำการขีดฆ่า item นั้น

ดังนั้นเราจะปรับอะไรนิดหน่อย จากเดิมที่เป็น array list ของ text เฉยๆ จะเป็น array list ของ object ตัวนึง ชื่อว่าอะไรดีน้า ชื่อ item ก็แล้วกัน ข้างในจะประกอบด้วย

  • done เป็น boolean ไว้ check ว่า อันนี้ถูกติ๊กแล้วหรือยัง
  • text เป็น text ธรรมดาเลย ว่า todo อันนี้ คืออะไร

จากเดิมที่เราจะอัพ todoList เมื่อมี input เข้ามา จะเป็นการเอา object ตัวนี้ไปใส่เข้าไปแทน แบบนี้เลย

function addTodo() {
    let item = {
        done: false,
        text: input,
    };
    todoList = [...todoList, item];
    console.log(todoList);
    input = '';
}

แน่นอนว่าเราสร้าง object item มาแล้ว เราจะต้องนำมาใช้งาน

  • checkbox จะทำการ bind ค่า จาก todo.done
  • text จะทำการ bind ค่า จาก todo.text

เมื่อเซฟมากดแล้วยังไม่ได้ถูกขีดฆ่าเหมือนเดิม เพราะ ไม่ได้ handle ขีดฆ่า

เราจะทำการ check ว่า ถ้า todo.done เป็น true ให้ขีดฆ่า text ถ้าไม่ก็แสดงปกติไปเลย

ซึ่งเราจะต้องใช้ if-else เราอธิบายรวดเลยแล้วกันเนอะ จากโค้ดตัวอย่างนี้

Svelte examples
Cybernetically enhanced web apps
{#if x > 10}
	<p>{x} is greater than 10</p>
{:else if 5 > x}
	<p>{x} is less than 5</p>
{:else}
	<p>{x} is between 5 and 10</p>
{/if}

เปิด if ด้วย # จบด้วย / ส่วน else และ else if ใส่ : นะ

แต่ในเคสนี้ใช้แค่ if-else ปกติเลย ก็จะมีแค่ #if, :else และ /if เนอะ แบบนี้ เราจะขีดฆ่าโดยใช้ <strike> เนอะ

{#each todoList as todo}
    <div class="flex flex-row">
        <input class="place-self-center" type=checkbox bind:checked={todo.done}>
        <p class="mx-4">
            {#if todo.done}
                <strike>{todo.text}</strike>
            {:else}
                {todo.text}
            {/if}
        </p>
    </div>
{/each}

ผลที่ได้จ้า

สวยงาม ถูกต้องจ้า เย้ๆ

โค้ดทั้งหมดจ้าทุกคน

<script>
    export let input = "";

    let todoList = [];

    function addTodo() {
        let item = {
            done: false,
            text: input,
        };
        todoList = [...todoList, item];
        console.log(todoList);
        input = '';
    }
</script>

<h1>TODO LIST</h1>

<input bind:value={input} placeholder="enter something">
<button on:click={addTodo}>
    Add
</button>

{#each todoList as todo}
    <div class="flex flex-row">
        <input class="place-self-center" type=checkbox bind:checked={todo.done}>
        <p class="mx-4">
            {#if todo.done}
                <strike>{todo.text}</strike>
            {:else}
                {todo.text}
            {/if}
        </p>
    </div>
{/each}

ลอกมาจาก

Svelte examples
Cybernetically enhanced web apps

ปรับให้สวยงามอีกนิดด้วย Tailwind CSS

มาดูจอทั้งหมดกัน

ชิดซ้ายไปเลยค้าบพี่

เราก็เลยขยายๆมันหน่อย เริ่มจากให้มันขยับออกจากมุมซ้ายบนหน่อย เพิ่มกรอบของ input และ button เพิ่มขนาด text หน่อย ก็น่าจะได้มั้งนะ

โค้ดทั้งหมดของเราในบล็อกนี้

GitHub - mikkipastel/svelte-todolist: sample todo list website with svelte and tailwind.css
sample todo list website with svelte and tailwind.css - GitHub - mikkipastel/svelte-todolist: sample todo list website with svelte and tailwind.css

ทิ้งท้าย

เราทำ template ของ Svelte เอาไว้แหละ ใช้ Svelte Kit + Tailwind CSS เอาไว้ใช้ในการขึ้นโปรเจกต่อๆไป

GitHub - mikkipastel/svelte-template
Contribute to mikkipastel/svelte-template development by creating an account on GitHub.

จริงๆคือคนทำกันเยอะมากเลยนะเจ้า template อ่ะ ชอบอันไหนก็เอาอันนั้นไปใช้ได้เลย

GitHub - ronnapatp/sveltekit-template
Contribute to ronnapatp/sveltekit-template development by creating an account on GitHub.
GitHub - bossoq/simple-sveltekit-template: Build a web app with Sveltekit, quickly.
Build a web app with Sveltekit, quickly. Contribute to bossoq/simple-sveltekit-template development by creating an account on GitHub.
GitHub - tinarskii/Sveltekit-TailwindCSS-template: Outdated, Use Sveltaily (https://github.com/thevvx/Sveltaily) instead
Outdated, Use Sveltaily (https://github.com/thevvx/Sveltaily) instead - GitHub - tinarskii/Sveltekit-TailwindCSS-template: Outdated, Use Sveltaily (https://github.com/thevvx/Sveltaily) instead
GitHub - narze/single-page-svelte: Build a single page app with Svelte, quickly.
Build a single page app with Svelte, quickly. Contribute to narze/single-page-svelte development by creating an account on GitHub.
GitHub - thevvx/Sveltaily: Template for building Svelte Kit web application with Tailwind CSS faster!
Template for building Svelte Kit web application with Tailwind CSS faster! - GitHub - thevvx/Sveltaily: Template for building Svelte Kit web application with Tailwind CSS faster!

ก็หวังว่าจะได้ความรู้กันไปเนอะ เอาจริงๆบล็อกนี้เขียนนานมาก แถมยังเอามาสตรีมอีก อ่ะดูย้อนหลังได้ที่นี่ เพราะ Twitch มันเก็บแค่ 14 วันอ่ะดิ


สามารถ support ค่ากาแฟเจ้าของบล็อกได้ที่ปุ่มแดงส้มสุดน่ารักที่มุมซ้ายล่าง หรือกดปุ่มตรงนี้ก็ได้จ้า

Buy Me a Coffee at ko-fi.com

ติดตามข่าวสารและบทความใหม่ๆได้ที่

อย่าลืมกด like กด share บทความกันด้วยนะคะ :)

Posted by MikkiPastel on Sunday, 10 December 2017

ช่องทางใหม่ ติดตามทุกๆสตรีมของเราได้ที่

Twitch
Twitch is the world’s leading video platform and community for gamers.
https://www.twitch.tv/mikkipastel

Subscribe ช่อง YouTube ของเราได้ที่

mikkicoding
Android Developer & Content Creator
https://www.youtube.com/c/mikkicoding

download แอพอ่านบล็อกใหม่ของเราได้ที่นี่

MikkiPastel - Apps on Google Play
First application from “MikkiPastel” on play store beta feature- read blog from https://www.mikkipastel.com by this application- read blog content by chrome custom tab- update or refresh new content by pull to refresh- share content to social network
https://play.google.com/store/apps/details?id=com.mikkipastel.blog

Tags

Minseo Chayabanjonglerd

I am a full-time Android Developer and part-time contributor with developer community and web3 world, who believe people have hard skills and soft skills to up-skill to da moon.