Proje Detayları
Adım Adım Geliştirme
Bu bölümde, sürükle ve bırak liste uygulamasını adım adım nasıl geliştirebileceğinizi öğreneceksiniz. Her adımda, ilgili kod parçalarını ve açıklamalarını bulacaksınız.
Adım 1: Proje Yapısını Oluşturma
İlk olarak, projemiz için gerekli dosyaları oluşturalım:
index.html
- Ana HTML dosyasıstyle.css
- CSS stil dosyasıscript.js
- JavaScript kod dosyası
<!DOCTYPE html>
<html lang="tr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Sürükle & Bırak Liste</title>
<link rel="stylesheet" href="style.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta3/css/all.min.css">
</head>
<body>
<div class="container">
<div class="drag-drop-container">
<div class="drag-drop-header">
<h1>Sürükle & Bırak Liste</h1>
<p>Öğeleri ekleyin, sürükleyin ve kategoriler arasında taşıyın</p>
</div>
<div class="drag-drop-controls">
<input type="text" class="drag-drop-input" id="dragDropInput" placeholder="Yeni öğe ekleyin...">
<button class="drag-drop-btn" id="dragDropAddBtn">Ekle</button>
</div>
<div class="drag-drop-categories">
<div class="drag-drop-category" id="todoCategory" data-category="todo">
<h2>Yapılacaklar</h2>
<ul class="drag-drop-category-list" id="todoList">
<!-- Liste öğeleri buraya eklenecek -->
</ul>
</div>
<div class="drag-drop-category" id="inProgressCategory" data-category="inProgress">
<h2>Devam Edenler</h2>
<ul class="drag-drop-category-list" id="inProgressList">
<!-- Liste öğeleri buraya eklenecek -->
</ul>
</div>
<div class="drag-drop-category" id="doneCategory" data-category="done">
<h2>Tamamlananlar</h2>
<ul class="drag-drop-category-list" id="doneList">
<!-- Liste öğeleri buraya eklenecek -->
</ul>
</div>
</div>
</div>
</div>
<script src="script.js"></script>
</body>
</html>
/* Genel Stiller */
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
background-color: #f5f5f5;
color: #333;
line-height: 1.6;
}
.container {
width: 100%;
max-width: 1200px;
margin: 0 auto;
padding: 20px;
}
/* Sürükle & Bırak Liste Stilleri */
.drag-drop-container {
width: 100%;
max-width: 900px;
margin: 0 auto;
}
.drag-drop-header {
text-align: center;
margin-bottom: 30px;
}
.drag-drop-header h1 {
font-size: 2.5rem;
color: #333;
margin-bottom: 10px;
}
.drag-drop-header p {
color: #666;
font-size: 1.1rem;
}
.drag-drop-controls {
display: flex;
justify-content: space-between;
margin-bottom: 20px;
}
.drag-drop-input {
flex: 1;
padding: 12px 15px;
border: 1px solid #ddd;
border-radius: 4px;
font-size: 1rem;
margin-right: 10px;
outline: none;
}
.drag-drop-input:focus {
border-color: #4caf50;
}
.drag-drop-btn {
background-color: #4caf50;
color: white;
border: none;
padding: 12px 20px;
border-radius: 4px;
cursor: pointer;
font-size: 1rem;
transition: background-color 0.3s;
}
.drag-drop-btn:hover {
background-color: #388e3c;
}
.drag-drop-categories {
display: flex;
gap: 20px;
}
.drag-drop-category {
flex: 1;
background-color: #fff;
border-radius: 8px;
padding: 20px;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
}
.drag-drop-category h2 {
margin-top: 0;
margin-bottom: 15px;
font-size: 1.5rem;
color: #333;
text-align: center;
padding-bottom: 10px;
border-bottom: 2px solid #f1f1f1;
}
.drag-drop-category-list {
min-height: 200px;
list-style-type: none;
padding: 0;
margin: 0;
}
.drag-drop-item {
background-color: #f9f9f9;
padding: 15px;
margin-bottom: 10px;
border-radius: 4px;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
cursor: move;
transition: all 0.3s;
display: flex;
justify-content: space-between;
align-items: center;
}
.drag-drop-item:hover {
background-color: #f1f1f1;
transform: translateY(-2px);
box-shadow: 0 4px 8px rgba(0,0,0,0.1);
}
.drag-drop-item.dragging {
opacity: 0.5;
background-color: #e0e0e0;
}
.drag-drop-item-content {
flex: 1;
}
.drag-drop-item-actions {
display: flex;
gap: 10px;
}
.drag-drop-item-actions button {
background: none;
border: none;
cursor: pointer;
font-size: 1rem;
color: #666;
transition: color 0.3s;
}
.drag-drop-item-actions button:hover {
color: #333;
}
.drag-drop-item-actions .edit-btn:hover {
color: #2196f3;
}
.drag-drop-item-actions .delete-btn:hover {
color: #f44336;
}
.drag-drop-item-handle {
cursor: move;
color: #999;
margin-right: 10px;
}
.drag-drop-category.highlight {
background-color: #e8f5e9;
border: 2px dashed #4caf50;
}
.drag-drop-empty {
text-align: center;
padding: 20px;
color: #999;
font-style: italic;
}
/* Responsive Tasarım */
@media (max-width: 768px) {
.drag-drop-categories {
flex-direction: column;
}
.drag-drop-category {
margin-bottom: 20px;
}
}
Adım 2: JavaScript Kodunu Yazma
Şimdi, uygulamanın işlevselliğini sağlayacak JavaScript kodunu yazalım:
// DOM elementlerini seçme
const dragDropInput = document.getElementById('dragDropInput');
const dragDropAddBtn = document.getElementById('dragDropAddBtn');
const todoList = document.getElementById('todoList');
const inProgressList = document.getElementById('inProgressList');
const doneList = document.getElementById('doneList');
const categories = document.querySelectorAll('.drag-drop-category');
// Değişkenler
let draggedItem = null;
let items = JSON.parse(localStorage.getItem('dragDropItems')) || {
todo: [
{ id: 1, content: 'JavaScript öğrenmek' },
{ id: 2, content: 'Proje geliştirmek' }
],
inProgress: [
{ id: 3, content: 'DOM manipülasyonu çalışmak' }
],
done: [
{ id: 4, content: 'HTML öğrenmek' }
]
};
let nextId = 5; // Başlangıç ID'si
// Sayfa yüklendiğinde
document.addEventListener('DOMContentLoaded', () => {
// Öğeleri yükle
loadItems();
// Yeni öğe ekleme
dragDropAddBtn.addEventListener('click', addItem);
dragDropInput.addEventListener('keypress', (e) => {
if (e.key === 'Enter') {
addItem();
}
});
// Sürükleme olayları için kategorileri ayarla
setupDragAndDrop();
});
// Öğeleri yükleme fonksiyonu
function loadItems() {
// Tüm listeleri temizle
todoList.innerHTML = '';
inProgressList.innerHTML = '';
doneList.innerHTML = '';
// Yapılacaklar listesi
if (items.todo.length === 0) {
todoList.innerHTML = 'Henüz öğe yok';
} else {
items.todo.forEach(item => {
const listItem = createListItem(item);
todoList.appendChild(listItem);
});
}
// Devam edenler listesi
if (items.inProgress.length === 0) {
inProgressList.innerHTML = 'Henüz öğe yok';
} else {
items.inProgress.forEach(item => {
const listItem = createListItem(item);
inProgressList.appendChild(listItem);
});
}
// Tamamlananlar listesi
if (items.done.length === 0) {
doneList.innerHTML = 'Henüz öğe yok';
} else {
items.done.forEach(item => {
const listItem = createListItem(item);
doneList.appendChild(listItem);
});
}
}
// Liste öğesi oluşturma fonksiyonu
function createListItem(item) {
const listItem = document.createElement('li');
listItem.className = 'drag-drop-item';
listItem.draggable = true;
listItem.dataset.id = item.id;
listItem.innerHTML = `
${item.content}
`;
// Düzenleme butonu için olay dinleyicisi
listItem.querySelector('.edit-btn').addEventListener('click', () => {
editItem(item.id);
});
// Silme butonu için olay dinleyicisi
listItem.querySelector('.delete-btn').addEventListener('click', () => {
deleteItem(item.id);
});
// Sürükleme olayları
listItem.addEventListener('dragstart', dragStart);
listItem.addEventListener('dragend', dragEnd);
return listItem;
}
// Yeni öğe ekleme fonksiyonu
function addItem() {
const content = dragDropInput.value.trim();
if (content !== '') {
// Boş öğe mesajını kaldır
const emptyMessage = todoList.querySelector('.drag-drop-empty');
if (emptyMessage) {
todoList.removeChild(emptyMessage);
}
// Yeni öğe oluştur
const newItem = {
id: nextId++,
content: content
};
// Öğeyi yapılacaklar listesine ekle
items.todo.push(newItem);
// Öğeyi DOM'a ekle
const listItem = createListItem(newItem);
todoList.appendChild(listItem);
// Giriş alanını temizle
dragDropInput.value = '';
// LocalStorage'a kaydet
saveItems();
}
}
// Öğe düzenleme fonksiyonu
function editItem(id) {
// Tüm kategorilerde öğeyi bul
let category = '';
let itemIndex = -1;
for (const cat of ['todo', 'inProgress', 'done']) {
const index = items[cat].findIndex(item => item.id === id);
if (index !== -1) {
category = cat;
itemIndex = index;
break;
}
}
if (category && itemIndex !== -1) {
const item = items[category][itemIndex];
const newContent = prompt('Öğeyi düzenleyin:', item.content);
if (newContent !== null && newContent.trim() !== '') {
// Öğeyi güncelle
item.content = newContent.trim();
// DOM'u güncelle
const listItem = document.querySelector(`.drag-drop-item[data-id="${id}"]`);
if (listItem) {
listItem.querySelector('.drag-drop-item-content').textContent = newContent.trim();
}
// LocalStorage'a kaydet
saveItems();
}
}
}
// Öğe silme fonksiyonu
function deleteItem(id) {
// Tüm kategorilerde öğeyi bul
let category = '';
let itemIndex = -1;
for (const cat of ['todo', 'inProgress', 'done']) {
const index = items[cat].findIndex(item => item.id === id);
if (index !== -1) {
category = cat;
itemIndex = index;
break;
}
}
if (category && itemIndex !== -1) {
// Öğeyi diziden kaldır
items[category].splice(itemIndex, 1);
// DOM'dan kaldır
const listItem = document.querySelector(`.drag-drop-item[data-id="${id}"]`);
if (listItem) {
listItem.parentElement.removeChild(listItem);
}
// Eğer liste boşsa, boş mesajı göster
if (items[category].length === 0) {
const list = document.getElementById(`${category}List`);
list.innerHTML = 'Henüz öğe yok';
}
// LocalStorage'a kaydet
saveItems();
}
}
// LocalStorage'a kaydetme fonksiyonu
function saveItems() {
localStorage.setItem('dragDropItems', JSON.stringify(items));
}
// Sürükleme başlangıç olayı
function dragStart(e) {
draggedItem = this;
setTimeout(() => {
this.classList.add('dragging');
}, 0);
// Veri transferi
e.dataTransfer.setData('text/plain', this.dataset.id);
e.dataTransfer.effectAllowed = 'move';
}
// Sürükleme bitiş olayı
function dragEnd() {
this.classList.remove('dragging');
draggedItem = null;
// Tüm kategorilerdeki vurgulamayı kaldır
categories.forEach(category => {
category.classList.remove('highlight');
});
}
// Sürükle ve bırak işlevselliğini ayarlama
function setupDragAndDrop() {
categories.forEach(category => {
// Sürükleme üzerinde olayı
category.addEventListener('dragover', (e) => {
e.preventDefault();
category.classList.add('highlight');
});
// Sürükleme dışına çıkma olayı
category.addEventListener('dragleave', () => {
category.classList.remove('highlight');
});
// Bırakma olayı
category.addEventListener('drop', (e) => {
e.preventDefault();
category.classList.remove('highlight');
const id = parseInt(e.dataTransfer.getData('text/plain'));
const targetCategory = category.dataset.category;
// Öğeyi eski kategorisinden bul ve kaldır
let sourceCategory = '';
let itemIndex = -1;
let item = null;
for (const cat of ['todo', 'inProgress', 'done']) {
const index = items[cat].findIndex(item => item.id === id);
if (index !== -1) {
sourceCategory = cat;
itemIndex = index;
item = items[cat][index];
break;
}
}
if (sourceCategory && itemIndex !== -1 && item) {
// Öğeyi eski kategorisinden kaldır
items[sourceCategory].splice(itemIndex, 1);
// Öğeyi yeni kategoriye ekle
items[targetCategory].push(item);
// DOM'u güncelle
loadItems();
// LocalStorage'a kaydet
saveItems();
}
});
});
}
Adım 3: Dokunmatik Cihaz Desteği Ekleme
Mobil cihazlarda sürükle ve bırak işlevselliğini desteklemek için aşağıdaki kodu ekleyelim:
// Dokunmatik cihaz desteği için ek kod
// Bu kodu script.js dosyasının sonuna ekleyin
// Dokunmatik cihaz kontrolü
const isTouchDevice = 'ontouchstart' in window || navigator.maxTouchPoints > 0 || navigator.msMaxTouchPoints > 0;
if (isTouchDevice) {
// Dokunmatik cihazlar için alternatif sürükleme yöntemi
setupTouchDragAndDrop();
}
function setupTouchDragAndDrop() {
// Tüm liste öğeleri için uzun basma olayı ekle
document.addEventListener('DOMContentLoaded', () => {
// Öğeler yüklendiğinde dokunmatik olayları ekle
addTouchEventsToItems();
});
}
function addTouchEventsToItems() {
const items = document.querySelectorAll('.drag-drop-item');
items.forEach(item => {
// Uzun basma için zamanlayıcı
let touchTimer;
let touchStartX, touchStartY;
let isTouching = false;
// Dokunma başlangıcı
item.addEventListener('touchstart', (e) => {
touchStartX = e.touches[0].clientX;
touchStartY = e.touches[0].clientY;
// Uzun basma algılama (500ms)
touchTimer = setTimeout(() => {
isTouching = true;
item.classList.add('dragging');
// Seçilen öğeyi göster
const clone = item.cloneNode(true);
clone.style.position = 'fixed';
clone.style.top = `${touchStartY - 30}px`;
clone.style.left = `${touchStartX - 30}px`;
clone.style.width = `${item.offsetWidth}px`;
clone.style.opacity = '0.8';
clone.style.zIndex = '1000';
clone.id = 'touchDragClone';
document.body.appendChild(clone);
// Kategorileri vurgula
categories.forEach(category => {
category.classList.add('highlight');
});
}, 500);
});
// Dokunma hareketi
item.addEventListener('touchmove', (e) => {
if (isTouching) {
e.preventDefault(); // Sayfanın kaydırılmasını engelle
const touchX = e.touches[0].clientX;
const touchY = e.touches[0].clientY;
// Klonu hareket ettir
const clone = document.getElementById('touchDragClone');
if (clone) {
clone.style.top = `${touchY - 30}px`;
clone.style.left = `${touchX - 30}px`;
}
// Hangi kategorinin üzerinde olduğunu kontrol et
categories.forEach(category => {
const rect = category.getBoundingClientRect();
if (
touchX >= rect.left &&
touchX <= rect.right &&
touchY >= rect.top &&
touchY <= rect.bottom
) {
category.classList.add('highlight');
} else {
category.classList.remove('highlight');
}
});
}
});
// Dokunma bitişi
item.addEventListener('touchend', (e) => {
clearTimeout(touchTimer);
if (isTouching) {
const touchX = e.changedTouches[0].clientX;
const touchY = e.changedTouches[0].clientY;
// Klonu kaldır
const clone = document.getElementById('touchDragClone');
if (clone) {
document.body.removeChild(clone);
}
// Hangi kategorinin üzerinde bırakıldığını kontrol et
categories.forEach(category => {
const rect = category.getBoundingClientRect();
if (
touchX >= rect.left &&
touchX <= rect.right &&
touchY >= rect.top &&
touchY <= rect.bottom
) {
// Öğeyi bu kategoriye taşı
const id = parseInt(item.dataset.id);
const targetCategory = category.dataset.category;
// Öğeyi eski kategorisinden bul ve kaldır
let sourceCategory = '';
let itemIndex = -1;
let itemObj = null;
for (const cat of ['todo', 'inProgress', 'done']) {
const index = items[cat].findIndex(i => i.id === id);
if (index !== -1) {
sourceCategory = cat;
itemIndex = index;
itemObj = items[cat][index];
break;
}
}
if (sourceCategory && itemIndex !== -1 && itemObj) {
// Öğeyi eski kategorisinden kaldır
items[sourceCategory].splice(itemIndex, 1);
// Öğeyi yeni kategoriye ekle
items[targetCategory].push(itemObj);
// DOM'u güncelle
loadItems();
// LocalStorage'a kaydet
saveItems();
}
}
});
// Tüm vurgulamaları kaldır
categories.forEach(category => {
category.classList.remove('highlight');
});
item.classList.remove('dragging');
isTouching = false;
}
});
// Dokunma iptali
item.addEventListener('touchcancel', () => {
clearTimeout(touchTimer);
if (isTouching) {
// Klonu kaldır
const clone = document.getElementById('touchDragClone');
if (clone) {
document.body.removeChild(clone);
}
// Tüm vurgulamaları kaldır
categories.forEach(category => {
category.classList.remove('highlight');
});
item.classList.remove('dragging');
isTouching = false;
}
});
});
}
// Yeni öğe eklendiğinde veya öğeler yüklendiğinde dokunmatik olayları ekle
function loadItems() {
// ... mevcut kod ...
// Dokunmatik cihaz desteği için
if (isTouchDevice) {
addTouchEventsToItems();
}
}
Adım 4: Uygulamayı Test Etme
Şimdi uygulamanızı test etme zamanı! Aşağıdaki adımları izleyin:
- Tüm dosyaları (
index.html
,style.css
,script.js
) aynı klasöre kaydedin. - HTML dosyasını bir web tarayıcısında açın.
- Giriş alanına metin yazarak ve "Ekle" butonuna tıklayarak yeni öğeler ekleyin.
- Öğeleri sürükleyerek farklı kategoriler arasında taşıyın.
- Düzenleme ve silme butonlarını kullanarak öğeleri düzenleyin veya silin.
- Sayfayı yenileyin ve öğelerin localStorage sayesinde korunduğunu doğrulayın.
- Mobil cihazda veya dokunmatik ekranda uzun basma ile sürükleme işlevini test edin.
İpucu: Tarayıcınızın geliştirici araçlarını (genellikle F12 tuşu ile açılır) kullanarak JavaScript hatalarını ayıklayabilirsiniz. Ayrıca, responsive tasarımı test etmek için tarayıcının ekran boyutunu değiştirebilirsiniz.
Projeyi Geliştirme
Temel sürükle ve bırak liste uygulamasını başarıyla oluşturduktan sonra, aşağıdaki özelliklerle projenizi geliştirebilirsiniz:
1. Öğe Önceliği ve Renk Kodlaması
Öğelere öncelik seviyesi ekleyin ve farklı öncelikleri renk kodlarıyla gösterin:
// Öğe veri yapısını güncelle
let items = JSON.parse(localStorage.getItem('dragDropItems')) || {
todo: [
{ id: 1, content: 'JavaScript öğrenmek', priority: 'high' },
{ id: 2, content: 'Proje geliştirmek', priority: 'medium' }
],
inProgress: [
{ id: 3, content: 'DOM manipülasyonu çalışmak', priority: 'medium' }
],
done: [
{ id: 4, content: 'HTML öğrenmek', priority: 'low' }
]
};
// Liste öğesi oluşturma fonksiyonunu güncelle
function createListItem(item) {
const listItem = document.createElement('li');
listItem.className = `drag-drop-item priority-${item.priority || 'medium'}`;
listItem.draggable = true;
listItem.dataset.id = item.id;
listItem.innerHTML = `
${item.content}
`;
// Düzenleme butonu için olay dinleyicisi
listItem.querySelector('.edit-btn').addEventListener('click', () => {
editItem(item.id);
});
// Silme butonu için olay dinleyicisi
listItem.querySelector('.delete-btn').addEventListener('click', () => {
deleteItem(item.id);
});
// Öncelik butonu için olay dinleyicisi
listItem.querySelector('.priority-btn').addEventListener('click', (e) => {
togglePriority(item.id);
});
// Sürükleme olayları
listItem.addEventListener('dragstart', dragStart);
listItem.addEventListener('dragend', dragEnd);
return listItem;
}
// Öncelik değiştirme fonksiyonu
function togglePriority(id) {
// Tüm kategorilerde öğeyi bul
let category = '';
let itemIndex = -1;
for (const cat of ['todo', 'inProgress', 'done']) {
const index = items[cat].findIndex(item => item.id === id);
if (index !== -1) {
category = cat;
itemIndex = index;
break;
}
}
if (category && itemIndex !== -1) {
const item = items[category][itemIndex];
const currentPriority = item.priority || 'medium';
// Önceliği değiştir (döngüsel: low -> medium -> high -> low)
if (currentPriority === 'low') {
item.priority = 'medium';
} else if (currentPriority === 'medium') {
item.priority = 'high';
} else {
item.priority = 'low';
}
// DOM'u güncelle
const listItem = document.querySelector(`.drag-drop-item[data-id="${id}"]`);
if (listItem) {
// Sınıfları güncelle
listItem.className = `drag-drop-item priority-${item.priority}`;
// Öncelik butonunu güncelle
const priorityBtn = listItem.querySelector('.priority-btn');
priorityBtn.dataset.priority = item.priority;
}
// LocalStorage'a kaydet
saveItems();
}
}
// CSS'e öncelik stilleri ekle
/*
.priority-high {
border-left: 4px solid #f44336;
}
.priority-medium {
border-left: 4px solid #ff9800;
}
.priority-low {
border-left: 4px solid #4caf50;
}
.priority-btn[data-priority="high"] {
color: #f44336;
}
.priority-btn[data-priority="medium"] {
color: #ff9800;
}
.priority-btn[data-priority="low"] {
color: #4caf50;
}
*/
2. Öğe Etiketleri
Öğelere etiketler ekleyerek daha iyi kategorilendirme yapın:
// Öğe veri yapısını güncelle
let items = JSON.parse(localStorage.getItem('dragDropItems')) || {
todo: [
{ id: 1, content: 'JavaScript öğrenmek', priority: 'high', tags: ['öğrenme', 'kodlama'] },
{ id: 2, content: 'Proje geliştirmek', priority: 'medium', tags: ['proje'] }
],
inProgress: [
{ id: 3, content: 'DOM manipülasyonu çalışmak', priority: 'medium', tags: ['öğrenme'] }
],
done: [
{ id: 4, content: 'HTML öğrenmek', priority: 'low', tags: ['öğrenme', 'tamamlandı'] }
]
};
// Liste öğesi oluşturma fonksiyonunu güncelle
function createListItem(item) {
const listItem = document.createElement('li');
listItem.className = `drag-drop-item priority-${item.priority || 'medium'}`;
listItem.draggable = true;
listItem.dataset.id = item.id;
// Etiketleri oluştur
let tagsHTML = '';
if (item.tags && item.tags.length > 0) {
tagsHTML = '';
item.tags.forEach(tag => {
tagsHTML += `${tag}`;
});
tagsHTML += '';
}
listItem.innerHTML = `
${item.content}
${tagsHTML}
`;
// Düzenleme butonu için olay dinleyicisi
listItem.querySelector('.edit-btn').addEventListener('click', () => {
editItem(item.id);
});
// Silme butonu için olay dinleyicisi
listItem.querySelector('.delete-btn').addEventListener('click', () => {
deleteItem(item.id);
});
// Öncelik butonu için olay dinleyicisi
listItem.querySelector('.priority-btn').addEventListener('click', () => {
togglePriority(item.id);
});
// Etiket butonu için olay dinleyicisi
listItem.querySelector('.tag-btn').addEventListener('click', () => {
editTags(item.id);
});
// Sürükleme olayları
listItem.addEventListener('dragstart', dragStart);
listItem.addEventListener('dragend', dragEnd);
return listItem;
}
// Etiketleri düzenleme fonksiyonu
function editTags(id) {
// Tüm kategorilerde öğeyi bul
let category = '';
let itemIndex = -1;
for (const cat of ['todo', 'inProgress', 'done']) {
const index = items[cat].findIndex(item => item.id === id);
if (index !== -1) {
category = cat;
itemIndex = index;
break;
}
}
if (category && itemIndex !== -1) {
const item = items[category][itemIndex];
const currentTags = item.tags ? item.tags.join(', ') : '';
const newTags = prompt('Etiketleri virgülle ayırarak girin:', currentTags);
if (newTags !== null) {
// Etiketleri güncelle
item.tags = newTags.split(',')
.map(tag => tag.trim())
.filter(tag => tag !== '');
// DOM'u güncelle
loadItems();
// LocalStorage'a kaydet
saveItems();
}
}
}
// CSS'e etiket stilleri ekle
/*
.drag-drop-item-tags {
display: flex;
flex-wrap: wrap;
gap: 5px;
margin-top: 5px;
}
.tag {
background-color: #e0e0e0;
color: #333;
padding: 2px 8px;
border-radius: 12px;
font-size: 0.8rem;
}
*/
3. Sürükle ve Bırak Sıralama
Aynı kategori içinde öğeleri sürükleyerek yeniden sıralama özelliği ekleyin:
// Sürükle ve bırak işlevselliğini ayarlama fonksiyonunu güncelle
function setupDragAndDrop() {
// Kategori listeleri
const lists = document.querySelectorAll('.drag-drop-category-list');
lists.forEach(list => {
// Sürükleme üzerinde olayı
list.addEventListener('dragover', (e) => {
e.preventDefault();
const afterElement = getDragAfterElement(list, e.clientY);
const draggable = document.querySelector('.dragging');
if (afterElement == null) {
list.appendChild(draggable);
} else {
list.insertBefore(draggable, afterElement);
}
});
});
// Kategoriler
categories.forEach(category => {
// Sürükleme üzerinde olayı
category.addEventListener('dragover', (e) => {
e.preventDefault();
category.classList.add('highlight');
});
// Sürükleme dışına çıkma olayı
category.addEventListener('dragleave', () => {
category.classList.remove('highlight');
});
// Bırakma olayı
category.addEventListener('drop', (e) => {
e.preventDefault();
category.classList.remove('highlight');
const id = parseInt(e.dataTransfer.getData('text/plain'));
const targetCategory = category.dataset.category;
// Öğeyi eski kategorisinden bul ve kaldır
let sourceCategory = '';
let itemIndex = -1;
let item = null;
for (const cat of ['todo', 'inProgress', 'done']) {
const index = items[cat].findIndex(item => item.id === id);
if (index !== -1) {
sourceCategory = cat;
itemIndex = index;
item = items[cat][index];
break;
}
}
if (sourceCategory && itemIndex !== -1 && item) {
// Öğeyi eski kategorisinden kaldır
items[sourceCategory].splice(itemIndex, 1);
// Öğeyi yeni kategoriye ekle
items[targetCategory].push(item);
// Yeni sıralamayı kaydet
updateItemsOrder();
// LocalStorage'a kaydet
saveItems();
}
});
});
}
// Sürüklenen öğenin bırakılacağı konumu belirleyen fonksiyon
function getDragAfterElement(container, y) {
const draggableElements = [...container.querySelectorAll('.drag-drop-item: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;
}
// Öğelerin yeni sıralamasını kaydetme fonksiyonu
function updateItemsOrder() {
// Tüm kategoriler için
for (const cat of ['todo', 'inProgress', 'done']) {
const list = document.getElementById(`${cat}List`);
const newOrder = [];
// Listedeki tüm öğeleri al
const listItems = list.querySelectorAll('.drag-drop-item');
// Her öğe için
listItems.forEach(item => {
const id = parseInt(item.dataset.id);
// Öğeyi items dizisinde bul
const itemObj = items[cat].find(i => i.id === id);
if (itemObj) {
newOrder.push(itemObj);
}
});
// Yeni sıralamayı kaydet
items[cat] = newOrder;
}
}
Geliştirme Zorlukları
Sürükle ve bırak liste uygulamanızı daha da geliştirmek için aşağıdaki zorlukları deneyebilirsiniz:
- Tarih ve Hatırlatıcılar: Öğelere son tarih ekleyin ve yaklaşan son tarihleri vurgulayın.
- Alt Görevler: Her öğeye alt görevler ekleyerek daha karmaşık görev yönetimi sağlayın.
- Filtreleme ve Arama: Etiketlere veya içeriğe göre öğeleri filtreleme ve arama özelliği ekleyin.
- Çoklu Kullanıcı Desteği: Farklı kullanıcılar için farklı listeler oluşturun.
- Veri Dışa/İçe Aktarma: Listeleri JSON formatında dışa ve içe aktarma özelliği ekleyin.
Sonuç ve Öğrenilen Dersler
Bu projede, JavaScript'in Drag & Drop API'sini kullanarak sürükle ve bırak işlevselliğine sahip bir liste uygulaması geliştirdik. Bu süreçte şunları öğrendik:
- HTML5 Drag & Drop API'sini kullanmayı
- Sürüklenebilir öğeler oluşturmayı ve yönetmeyi
- Sürükleme olaylarını (dragstart, dragover, drop vb.) kullanmayı
- Öğeleri dinamik olarak eklemeyi, düzenlemeyi ve silmeyi
- Kategoriler arasında öğe taşıma işlevselliği eklemeyi
- Yerel depolama (localStorage) kullanarak verileri kalıcı hale getirmeyi
- Dokunmatik cihazlar için sürükle ve bırak desteği eklemeyi
- Kullanıcı deneyimini geliştirmek için görsel geri bildirimler eklemeyi
Bu proje, modern web uygulamalarında yaygın olarak kullanılan sürükle ve bırak işlevselliğini nasıl uygulayacağınızı öğrenmenize yardımcı olmuştur. Öğrendiğiniz teknikleri ve kavramları kullanarak, daha karmaşık ve tam özellikli liste uygulamaları, kanban panoları veya diğer sürükle ve bırak tabanlı arayüzler geliştirebilirsiniz.