Yapılacaklar uygulaması
Bu sayfada
Ön yüz frameworkü olmadan klasik bir etkileşimli arayüz. sitelo sayfa kabuğunu kurar; olay öznitelikleri import('/js/todo.js').then(…) çağırır, böylece modül yalnızca gerektiğinde yüklenir. Tam kaynak examples/todo içinde.
Elinize geçenler
onsubmit/onload(ve liste öğesi) işleyicileriyle statik HTMLsrc/js/todo.js— dışa aktarılmışhydrate,handleSubmit,handleChange,handleRemove- sitelo, HTML içindeki düz
import('/…')ifadelerini keşfeder ve dosyayıdist/içine paketler (bkz. Varlıklar)
Proje düzeni
my-todo/
sitelo.config.js
package.json
src/
index.ht.js # statik kabuk + satır içi import() işleyicileri
css/
styles.css
js/
todo.js # dışa aktarılan işleyiciler (istendiğinde yüklenir)1. Sayfadaki satır içi içe aktarmalar
<script type="module" src> yok. İşleyiciler, modülü dinamik olarak içe aktaran ve this (öğenin kendisi) geçirerek bir dışa aktarımı çağıran HTML öznitelikleridir. Bu, sayfa modüllerini tarayıcı API’lerinden uzak tutar (bkz. JSX kısıtlamaları).
export default () => `
<html lang="tr">
<head>
<title>Yapılacaklar — sitelo</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="/css/styles.css">
</head>
<body onload="import('/js/todo.js').then((m) => m.hydrate())">
<main>
<h1>Yapılacaklar</h1>
<form
id="todo-form"
autocomplete="off"
onsubmit="event.preventDefault(); import('/js/todo.js').then((m) => m.handleSubmit(this))"
>
<input id="todo-input" name="title" type="text" placeholder="Ne yapılması gerekiyor?" required>
<button type="submit">Ekle</button>
</form>
<ul id="todo-list"></ul>
<p id="todo-empty" class="empty" hidden>Burada henüz bir şey yok.</p>
<p class="meta"><span id="todo-count">0</span> kaldı</p>
</main>
</body>
</html>
`import {
html, head, title, meta, link, body, main, h1, form, input, button, ul, p, span,
} from 'javascript-to-html'
export default () =>
html({ lang: 'tr' },
head(
title('Yapılacaklar — sitelo'),
meta({ name: 'viewport', content: 'width=device-width, initial-scale=1' }),
link({ rel: 'stylesheet', href: '/styles.css' }),
),
body(
{ onload: "import('/js/todo.js').then((m) => m.hydrate())" },
main(
h1('Yapılacaklar'),
form(
{
id: 'todo-form',
autocomplete: 'off',
onsubmit:
"event.preventDefault(); import('/js/todo.js').then((m) => m.handleSubmit(this))",
},
input({
id: 'todo-input',
name: 'title',
type: 'text',
placeholder: 'Ne yapılması gerekiyor?',
required: '',
}),
button({ type: 'submit' }, 'Ekle'),
),
ul({ id: 'todo-list' }),
p({ id: 'todo-empty', class: 'empty', hidden: '' }, 'Burada henüz bir şey yok.'),
p({ class: 'meta' }, span({ id: 'todo-count' }, '0'), ' kaldı'),
),
),
)export default function Todos() {
return (
<html lang="tr">
<head>
<title>Yapılacaklar — sitelo</title>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="stylesheet" href="/css/styles.css" />
</head>
<body
{...{
// React onLoad’ı sentetik olaya eşler; spread ham onload="" yazmamızı sağlar
onload: "import('/js/todo.js').then((m) => m.hydrate())",
}}
>
<main>
<h1>Yapılacaklar</h1>
<form
id="todo-form"
autoComplete="off"
{...{
// aynı sebep — React’in onSubmit’i değil, ham onsubmit=""
onsubmit:
"event.preventDefault(); import('/js/todo.js').then((m) => m.handleSubmit(this))",
}}
>
<input
id="todo-input"
name="title"
type="text"
placeholder="Ne yapılması gerekiyor?"
required
/>
<button type="submit">Ekle</button>
</form>
<ul id="todo-list" />
<p id="todo-empty" className="empty" hidden>
Burada henüz bir şey yok.
</p>
<p className="meta">
<span id="todo-count">0</span> kaldı
</p>
</main>
</body>
</html>
)
}2. Dışa aktarılmış işleyiciler
Modül, src/js/ altında normal bir ES dosyasıdır. Çalışma anında oluşturulan liste öğeleri onchange / onclick için aynı import('/js/todo.js').then(…) kalıbını kullanır.
import { button, input, label, li, span } from 'javascript-to-html'
const STORAGE_KEY = 'sitelo-todo-example'
function loadTodos() {
try {
const raw = localStorage.getItem(STORAGE_KEY)
if (!raw) return []
const parsed = JSON.parse(raw)
return Array.isArray(parsed) ? parsed : []
} catch {
return []
}
}
function saveTodos(todos) {
localStorage.setItem(STORAGE_KEY, JSON.stringify(todos))
}
function createId() {
return `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`
}
const IMPORT_CHANGE = "import('/js/todo.js').then((m) => m.handleChange(this))"
const IMPORT_REMOVE = "import('/js/todo.js').then((m) => m.handleRemove(this))"
function render() {
const list = document.querySelector('#todo-list')
const empty = document.querySelector('#todo-empty')
const count = document.querySelector('#todo-count')
if (!list || !empty || !count) return
const todos = loadTodos()
list.innerHTML = todos
.map((todo) =>
li(
{
class: todo.done ? 'todo is-done' : 'todo',
'data-id': todo.id,
},
label(
input({
type: 'checkbox',
onchange: IMPORT_CHANGE,
'aria-label': `İşaretle: "${todo.title}" tamamlandı`,
}),
span({ class: 'todo-title' }, todo.title),
),
button(
{
type: 'button',
class: 'todo-remove',
onclick: IMPORT_REMOVE,
'aria-label': `Kaldır "${todo.title}"`,
},
'Kaldır',
),
),
)
.join('')
for (const cb of list.querySelectorAll('input[type="checkbox"]')) {
const item = cb.closest('[data-id]')
const todo = todos.find((t) => t.id === item?.dataset.id)
if (todo) cb.checked = todo.done
}
count.textContent = String(todos.filter((t) => !t.done).length)
empty.hidden = todos.length > 0
}
export function hydrate() {
render()
}
export function handleSubmit(form) {
const input = form.elements.namedItem('title')
if (!(input instanceof HTMLInputElement)) return
const title = input.value.trim()
if (!title) return
saveTodos([{ id: createId(), title, done: false }, ...loadTodos()])
input.value = ''
input.focus()
render()
}
export function handleChange(checkbox) {
const item = checkbox.closest('[data-id]')
if (!(item instanceof HTMLElement) || !item.dataset.id) return
saveTodos(
loadTodos().map((todo) =>
todo.id === item.dataset.id ? { ...todo, done: checkbox.checked } : todo,
),
)
render()
}
export function handleRemove(button) {
const item = button.closest('[data-id]')
if (!(item instanceof HTMLElement) || !item.dataset.id) return
saveTodos(loadTodos().filter((todo) => todo.id !== item.dataset.id))
render()
}3. Çalıştırma
npm install
npm run devYa da npm run build çalıştırın ve dist/ dizinini statik dosya sunulan herhangi bir yerde barındırın.
Varlıklar ve stil · JSX kısıtlamaları · Temel site