
Dulu, waktu pertama kali nyemplung ke dunia koding, ada satu momen yang bikin saya garuk-garuk kepala sampai rambut rasanya mau rontok. Saya lagi mencoba bikin kalkulator sederhana, tapi hasilnya selalu NaN alias Not a Number. Setelah berjam-jam mondar-mandir, akhirnya ketemu biang keroknya: saya lupa mengonversi input dari teks ke angka di JavaScript! Rasanya kayak lagi ngebangun mesin, semua komponen udah terpasang, tapi lupa masukin bahan bakarnya. Momen "pencerahan" kecil itu mengajarkan saya betapa pentingnya detail dan pemahaman mendalam tentang setiap "bahan" yang kita pakai.
Nah, dari pengalaman receh seperti itulah kita bisa belajar banyak. Hari ini, kita akan sama-sama "merakit" dua aplikasi web yang mungkin terlihat sederhana tapi punya potensi besar: sebuah kalkulator web fungsional dan, yang lebih seru lagi, sebuah "page builder" mini. Keduanya akan kita bangun hanya dengan tiga serangkai sakti mandraguna: HTML sebagai rangkanya, CSS sebagai penata gayanya, dan JavaScript sebagai otaknya. Siap menyulap ide menjadi kode? Mari kita mulai!
Menggenggam Angka: Merakit Kalkulator Web Sederhana
Bayangkan kalkulator itu seperti sebuah timbangan dapur digital. Fungsinya simpel, tapi esensial: menghitung. Kita input bahan, dia kasih tahu beratnya. Kalkulator web juga begitu. Kita masukkan angka dan operator, dia kasih hasil. Lalu, bagaimana cara kita "merakit" timbangan digital ini?
1. Pondasi Kokoh dengan HTML
HTML adalah kerangka utama kalkulator kita, ibaratnya body timbangan. Kita butuh sebuah layar untuk menampilkan hasil dan tombol-tombol untuk angka serta operator.
<div class="calculator">
<input type="text" class="calculator-screen" value="0" disabled />
<div class="calculator-keys">
<button class="operator" value="+">+</button>
<button class="operator" value="-">-</button>
<button class="operator" value="*">×</button>
<button class="operator" value="/">÷</button>
<button value="7">7</button>
<button value="8">8</button>
<button value="9">9</button>
<button value="4">4</button>
<button value="5">5</button>
<button value="6">6</button>
<button value="1">1</button>
<button value="2">2</button>
<button value="3">3</button>
<button value="0">0</button>
<button class="decimal" value=".">.</button>
<button class="all-clear" value="all-clear">AC</button>
<button class="equal-sign operator" value="=">=</button>
</div>
</div>
Cukup sederhana, bukan? Kita punya satu input untuk layar dan satu div untuk membungkus semua tombol.
2. Mempercantik dengan CSS
Setelah kerangkanya jadi, saatnya memberi "cat" dan "desain" pada timbangan kita. CSS akan membuat kalkulator kita enak dipandang dan mudah digunakan.
.calculator {
border: 1px solid #ccc;
border-radius: 5px;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 400px;
}
.calculator-screen {
width: 100%;
height: 80px;
border: none;
background-color: #252525;
color: #fff;
text-align: right;
padding-right: 20px;
font-size: 4em;
border-top-left-radius: 5px;
border-top-right-radius: 5px;
}
.calculator-keys {
display: grid;
grid-template-columns: repeat(4, 1fr);
grid-gap: 1px;
background-color: #eee;
padding: 1px;
}
.calculator-keys button {
height: 60px;
background-color: #fff;
border: 1px solid #ccc;
font-size: 2em;
color: #333;
cursor: pointer;
}
.calculator-keys button:hover {
background-color: #ddd;
}
.operator {
background-color: #f79234;
color: #fff;
}
.equal-sign {
background-color: #2e86c0;
grid-column: -2 / -1; /* Mengambil dua kolom terakhir */
}
.all-clear {
background-color: #d12f2f;
color: #fff;
}
Dengan sedikit CSS Grid, kita bisa menata tombol-tombol itu dengan rapi seperti keyboard kalkulator sungguhan.
3. Menghidupkan dengan JavaScript
Ini adalah "otak" dari timbangan kita. JavaScript yang akan mendengarkan setiap tombol yang ditekan, melakukan perhitungan, dan menampilkan hasilnya di layar.
const calculator = document.querySelector('.calculator');
const keys = calculator.querySelector('.calculator-keys');
const display = calculator.querySelector('.calculator-screen');
let firstValue = null;
let operator = null;
let waitingForSecondValue = false;
keys.addEventListener('click', e => {
if (!e.target.matches('button')) return;
const key = e.target;
const action = key.dataset.action;
const keyContent = key.textContent;
const displayedNum = display.value;
if (!action) {
if (displayedNum === '0' || waitingForSecondValue) {
display.value = keyContent;
waitingForSecondValue = false;
} else {
display.value = displayedNum + keyContent;
}
}
if (action === 'add' || action === 'subtract' || action === 'multiply' || action === 'divide') {
firstValue = parseFloat(displayedNum);
operator = action;
waitingForSecondValue = true;
}
if (action === 'decimal') {
if (!displayedNum.includes('.')) {
display.value = displayedNum + '.';
}
if (waitingForSecondValue) {
display.value = '0.';
}
}
if (action === 'clear') {
display.value = '0';
firstValue = null;
operator = null;
waitingForSecondValue = false;
}
if (action === 'calculate') {
const secondValue = parseFloat(displayedNum);
let result = '';
if (operator === 'add') {
result = firstValue + secondValue;
} else if (operator === 'subtract') {
result = firstValue - secondValue;
} else if (operator === 'multiply') {
result = firstValue * secondValue;
} else if (operator === 'divide') {
result = firstValue / secondValue;
}
display.value = result;
firstValue = result; // Untuk perhitungan berantai
operator = null;
waitingForSecondValue = true;
}
});
Kode di atas adalah versi sederhana, namun sudah menunjukkan bagaimana JavaScript "mendengarkan" klik tombol, menyimpan angka, operator, dan akhirnya melakukan perhitungan. Ini baru awal dari petualangan kita!
Melangkah Lebih Jauh: Membangun "Page Builder" ala Bengkel Kustom
Jika kalkulator adalah timbangan dapur, maka "page builder" adalah seperti bengkel modifikasi mobil kustom. Kita tidak hanya menggunakan alat yang sudah ada, tapi juga merancang, menambah, dan mengubah bagian-bagian mobil sesuai keinginan. Di sini, "mobil" itu adalah halaman web, dan kita akan "memodifikasinya" secara dinamis.
Konsep inti dari page builder adalah memungkinkan pengguna untuk menambah, memindahkan, dan mengedit elemen-elemen HTML (seperti teks, gambar, tombol) langsung di browser tanpa perlu menyentuh kode. Ini adalah demonstrasi nyata kekuatan JavaScript dalam memanipulasi DOM (Document Object Model).
1. Pondasi Area Kerja dengan HTML
Kita butuh sebuah area di mana pengguna bisa melihat dan memanipulasi halaman, serta sebuah "panel kontrol" untuk menambahkan elemen.
<div class="page-builder-container">
<div class="sidebar">
<h3>Elemen</h3>
<ul>
<li draggable="true" data-type="header">Header</li>
<li draggable="true" data-type="paragraph">Paragraf</li>
<li draggable="true" data-type="image">Gambar</li>
<li draggable="true" data-type="button">Tombol</li>
</ul>
</div>
<div class="canvas" id="drop-area">
<!-- Elemen yang didrop akan muncul di sini -->
<p style="text-align: center; color: #aaa; margin-top: 50px;">Seret elemen ke sini!</p>
</div>
</div>
Di sini kita punya .sidebar yang berisi elemen-elemen yang bisa diseret, dan .canvas sebagai area di mana elemen tersebut akan "dipasang".
2. Mendesain Bengkel dengan CSS
Tampilan yang rapi dan interaktif sangat penting agar pengguna merasa nyaman "memodifikasi" halamannya.
.page-builder-container {
display: flex;
height: calc(100vh - 20px); /* Kurangi tinggi header/footer jika ada */
border: 1px solid #ddd;
box-shadow: 0 0 10px rgba(0,0,0,0.1);
}
.sidebar {
width: 250px;
background-color: #f8f8f8;
border-right: 1px solid #eee;
padding: 20px;
}
.sidebar ul {
list-style: none;
padding: 0;
}
.sidebar li {
background-color: #fff;
border: 1px solid #ccc;
padding: 10px 15px;
margin-bottom: 10px;
cursor: grab;
border-radius: 4px;
box-shadow: 0 1px 2px rgba(0,0,0,0.05);
}
.sidebar li:hover {
background-color: #eef;
}
.canvas {
flex-grow: 1;
background-color: #fff;
padding: 30px;
border: 2px dashed #eee;
display: flex;
flex-direction: column;
gap: 15px; /* Spasi antar elemen yang didrop */
overflow-y: auto;
}
.canvas.drag-over {
border-color: #007bff;
background-color: #e7f3ff;
}
/* Gaya untuk elemen yang didrop */
.canvas > * {
padding: 10px;
border: 1px solid #e0e0e0;
background-color: #fdfdfd;
cursor: move;
min-height: 40px; /* Agar mudah di-drag */
transition: all 0.2s ease-in-out;
}
.canvas > *:hover {
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
border-color: #a0a0a0;
}
CSS ini memberikan "bengkel" kita tampilan yang bersih dan fungsional, dengan area seret-lepas yang jelas.
3. Mengoperasikan Bengkel dengan JavaScript
Ini adalah bagian paling seru! JavaScript akan menangani semua interaksi: menyeret elemen dari sidebar ke canvas, menambahkannya ke DOM, bahkan memindahkannya di dalam canvas.
const draggables = document.querySelectorAll('.sidebar li');
const dropArea = document.getElementById('drop-area');
let draggedElement = null;
// Menangani drag dari sidebar
draggables.forEach(draggable => {
draggable.addEventListener('dragstart', (e) => {
draggedElement = e.target;
e.dataTransfer.setData('text/plain', e.target.dataset.type);
});
});
// Menangani drop di canvas
dropArea.addEventListener('dragover', (e) => {
e.preventDefault(); // Mencegah perilaku default browser
dropArea.classList.add('drag-over');
});
dropArea.addEventListener('dragleave', () => {
dropArea.classList.remove('drag-over');
});
dropArea.addEventListener('drop', (e) => {
e.preventDefault();
dropArea.classList.remove('drag-over');
const elementType = e.dataTransfer.getData('text/plain');
let newElement;
if (elementType === 'header') {
newElement = document.createElement('h2');
newElement.textContent = 'Ini Header Baru';
} else if (elementType === 'paragraph') {
newElement = document.createElement('p');
newElement.textContent = 'Ini paragraf baru yang bisa kamu edit.';
} else if (elementType === 'image') {
newElement = document.createElement('img');
newElement.src = 'https://via.placeholder.com/150'; // Contoh placeholder
newElement.alt = 'Gambar Placeholder';
newElement.style.maxWidth = '100%';
newElement.style.height = 'auto';
} else if (elementType === 'button') {
newElement = document.createElement('button');
newElement.textContent = 'Klik Saya!';
newElement.style.padding = '10px 20px';
newElement.style.backgroundColor = '#007bff';
newElement.style.color = '#fff';
newElement.style.border = 'none';
newElement.style.borderRadius = '5px';
newElement.style.cursor = 'pointer';
}
if (newElement) {
newElement.setAttribute('contenteditable', 'true'); // Agar bisa di-edit langsung
newElement.setAttribute('draggable', 'true'); // Agar bisa di-drag di dalam canvas
dropArea.appendChild(newElement);
}
});
// Menangani drag & drop elemen di dalam canvas (lebih kompleks, perlu logika re-ordering)
dropArea.addEventListener('dragstart', (e) => {
if (e.target.parentNode === dropArea) { // Pastikan elemen yang didrag adalah child dari dropArea
draggedElement = e.target;
e.dataTransfer.effectAllowed = 'move';
e.dataTransfer.setData('text/html', draggedElement.outerHTML);
draggedElement.style.opacity = '0.5';
}
});
dropArea.addEventListener('dragend', () => {
if (draggedElement) {
draggedElement.style.opacity = '1';
draggedElement = null;
}
});
dropArea.addEventListener('dragover', (e) => {
e.preventDefault();
const afterElement = getDragAfterElement(dropArea, e.clientY);
const draggable = document.querySelector('.canvas > .dragging'); // Jika ada elemen yang sedang di-drag
if (draggable) {
if (afterElement == null) {
dropArea.appendChild(draggable);
} else {
dropArea.insertBefore(draggable, afterElement);
}
}
});
// Fungsi pembantu untuk menentukan posisi drop
function getDragAfterElement(container, y) {
const draggableElements = [...container.querySelectorAll('.canvas > *:not(.dragging)')];
return draggableElements.reduce((closest, child) => {
const box = child.getBoundingClientRect();
const offset = y - box.top - box.height / 2;
if (offset < 0 && offset > closest.offset) {
return { offset: offset, element: child };
} else {
return closest;
}
}, { offset: Number.NEGATIVE_INFINITY }).element;
}
Kode di atas adalah permulaan. Kita menggunakan event dragstart, dragover, dragleave, dan drop untuk mengelola interaksi seret-lepas. Ketika sebuah elemen di-drop, JavaScript akan membuat elemen HTML baru (misalnya <h2> atau <p>) dan menambahkannya ke area canvas. Kita juga menambahkan atribut contenteditable="true" agar teksnya bisa langsung diedit oleh pengguna, mirip seperti di page builder sungguhan!
Tim Solid Kita: HTML, CSS, dan JavaScript
Dari dua contoh di atas, kita bisa melihat bagaimana ketiga teknologi ini bekerja sama seperti tim mekanik di bengkel mobil:
- HTML (Sang Arsitek / Kerangka Mobil): Dia adalah tulang punggung dari segalanya. Tanpa HTML, tidak akan ada elemen yang bisa kita lihat atau interaksikan. HTML mendefinisikan struktur dan konten dasar aplikasi kita. Ibarat rangka mobil, tempat semua komponen lain akan dipasang.
- CSS (Sang Desainer / Pengecat Mobil): Setelah rangka jadi, CSS bertugas mempercantik dan menata semuanya. Dari warna, ukuran, hingga posisi elemen. CSS membuat aplikasi kita enak dilihat dan mudah digunakan, seperti cat mobil yang mengkilap dan interior yang ergonomis.
- JavaScript (Sang Mekanik / Otak Mobil): Ini adalah bagian yang menghidupkan semuanya. JavaScript mendengarkan setiap interaksi pengguna (klik, seret, ketik), melakukan perhitungan, memanipulasi elemen di halaman (menambah, menghapus, mengubah), dan membuat aplikasi kita dinamis dan interaktif. Ini adalah mesin yang menggerakkan mobil kita, lengkap dengan sistem kelistrikan dan komputerisasi.
Menutup Perjalanan: Menjadi "Tukang Las" yang Kreatif
Membangun kalkulator atau page builder mini dengan HTML, CSS, dan JavaScript memang baru permulaan. Namun, ini menunjukkan potensi luar biasa dari tiga teknologi dasar ini. Kita bisa mulai dari hal yang sangat sederhana seperti kalkulator, yang melatih logika dan penanganan event, lalu berkembang ke proyek yang lebih kompleks dan interaktif seperti page builder, yang melibatkan manipulasi DOM yang intensif dan interaksi drag-and-drop.
Pesan saya, jangan takut untuk bereksperimen. Anggap saja setiap error itu seperti baut yang kendor, dan setiap solusi yang kamu temukan adalah alat baru di kotak perkakasmu. Teruslah "mengelas" dan "merakit" ide-idemu. Siapa tahu, dari iseng-iseng bikin kalkulator, kamu bisa menciptakan "mesin" web revolusioner berikutnya!
Selamat mencoba dan semoga kodingmu selalu lancar tanpa NaN!