يوم جيد يا اصدقاء!اليوم ، كما يوحي الاسم ، سنكتب تطبيقًا بسيطًا لإنشاء الملاحظات وتخزينها.ستكون ميزات تطبيقنا على النحو التالي:- قم بإنشاء ملاحظة.
- تخزين الملاحظات.
- حذف ملاحظة.
- ضع علامة على المهمة.
- معلومات حول تاريخ إتمام المهمة.
- تذكير لإكمال المهمة.
سيتم كتابة التطبيق في جافا سكريبت.سيتم تخزين الملاحظات في قاعدة بيانات مفهرسة (IndexedDB). سيتم استخدام هذه المكتبة لتسهيل العمل مع IndexedDB . وبحسب مطوري هذه المكتبة ، فهي "مثل IndexedDB ، ولكن مع وعود".من المفترض أنك معتاد على أساسيات قاعدة البيانات المفهرسة. إذا لم يكن الأمر كذلك ، فإنني أوصي بقراءة هذه المقالة قبل المتابعة .أفهم أنه لحل مشكلة مثل تخزين الملاحظات ، فإن LocalStorage يكفي. ومع ذلك ، أردت استكشاف بعض ميزات IndexedDB. وهكذا ، تم اختيار الخيار الأخير فقط من الاعتبارات المعرفية. في النهاية ، ستجد روابط لتطبيق مشابه حيث يتم تنفيذ تخزين البيانات باستخدام LocalStorage.إذن هيا بنا نذهب.يبدو ترميزنا كما يلي:
<link href="https://fonts.googleapis.com/css2?family=Stylish&display=swap" rel="stylesheet">
<script src="https://cdn.jsdelivr.net/npm/idb@3.0.2/build/idb.min.js"></script>
<div class="box">
<img src="https://placeimg.com/480/240/nature" alt="#">
<p>Note text: </p>
<textarea></textarea>
<p>Notification date: </p>
<input type="date">
<button class="add-btn">add note</button>
<button class="clear-btn">clear storage</button>
</div>
ملاحظات:- يمكن إنشاء حقول الإدخال باستخدام العلامتين "الشكل" و "الشكل". سيكون أكثر دلالة ، إذا جاز التعبير.
- كما اتضح لاحقًا ، لم يكن اختيار علامة "الإدخال" من نوع "التاريخ" هو الحل الأفضل. حول ذلك أدناه.
- في تطبيق واحد ، يتم تنفيذ التذكيرات (الإخطارات) باستخدام واجهة برمجة التطبيقات الخاصة بالإشعارات. ومع ذلك ، بدا غريباً أن أطلب من المستخدم إذنًا لعرض الإخطارات وإضافة القدرة على إيقاف تشغيلها ، لأنه ، أولاً ، عندما نتحدث عن تطبيق الملاحظات (المهام) ، يتم تضمين التذكيرات ، وثانيًا ، يمكن تنفيذها بحيث لا تزعج المستخدم عند الظهور المتكرر ، أي بشكل غير ملحوظ.
- في البداية ، وفر التطبيق القدرة على الإشارة ليس فقط إلى التاريخ ، ولكن أيضًا إلى وقت التذكير. بعد ذلك ، قررت أن التاريخ كافٍ. ومع ذلك ، إذا رغبت في ذلك ، فمن السهل إضافتها.
نحن نربط الأنماط:* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
height: 100vh;
background: radial-gradient(circle, skyblue, steelblue);
display: flex;
flex-wrap: wrap;
justify-content: center;
align-items: center;
font-family: 'Stylish', sans-serif;
font-size: 1.2em;
}
.box,
.list {
margin: 0 .4em;
width: 320px;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
background: linear-gradient(lightyellow, darkorange);
border-radius: 5px;
padding: .6em;
box-shadow: 0 0 4px rgba(0, 0, 0, .6)
}
img {
padding: .4em;
width: 100%;
}
h3 {
user-select: none;
}
p {
margin: .2em 0;
font-size: 1.1em;
}
textarea {
width: 300px;
height: 80px;
padding: .4em;
border-radius: 5px;
font-size: 1em;
resize: none;
margin-bottom: .7em;
}
input[type="date"] {
width: 150px;
text-align: center;
margin-bottom: 3em;
}
button {
width: 140px;
padding: .4em;
margin: .4em 0;
cursor: pointer;
border: none;
background: linear-gradient(lightgreen, darkgreen);
border-radius: 5px;
font-family: inherit;
font-size: .8em;
text-transform: uppercase;
box-shadow: 0 2px 2px rgba(0, 0, 0, .5);
}
button:active {
box-shadow: 0 1px 1px rgba(0, 0, 0, .7);
}
button:focus,
textarea:focus,
input:focus {
outline: none;
}
.note {
display: flex;
flex-wrap: wrap;
justify-content: center;
align-items: center;
font-style: italic;
user-select: none;
word-break: break-all;
position: relative;
}
.note p {
width: 240px;
font-size: 1em;
}
.note span {
display: block;
cursor: pointer;
font-weight: bold;
font-style: normal;
}
.info {
color: blue;
}
.notify {
color: #ddd;
font-size: .9em;
font-weight: normal !important;
text-align: center;
line-height: 25px;
border-radius: 5px;
width: 130px;
height: 25px;
position: absolute;
top: -10px;
left: -65px;
background: rgba(0, 0, 0, .6);
transition: .2s;
opacity: 0;
}
.show {
opacity: 1;
}
.info.null,
.notify.null {
display: none;
}
.complete {
padding: 0 .4em;
color: green;
}
.delete {
padding-left: .4em;
color: red;
}
.line-through {
text-decoration: line-through;
}
لا توليهم الكثير من الاهتمام حتى الآن.ننتقل إلى البرنامج النصي.ابحث عن حقول الإدخال وأنشئ حاوية للملاحظات:let textarea = document.querySelector('textarea')
let dateInput = document.querySelector('input[type="date"]')
let list = document.createElement('div')
list.classList.add('list')
document.body.appendChild(list)
إنشاء قاعدة بيانات وتخزين:let db;
(async () => {
db = await idb.openDb('db', 1, db => {
db.createObjectStore('notes', {
keyPath: 'id'
})
})
createList()
})();
ضع في اعتبارك وظيفة إضافة الملاحظات لفهم ماهية ملاحظة واحدة ، أو بشكل أكثر دقة ، ما تحتويه. سيساعد هذا على فهم كيفية تكوين القائمة:
document.querySelector('.add-btn').onclick = addNote
const addNote = async () => {
if (textarea.value === '') return
let text = textarea.value
let date
dateInput.value === '' ? date = null : date = dateInput.value
let note = {
id: id,
text: text,
createdDate: new Date().toLocaleDateString(),
completed: '',
notifyDate: date
}
try {
await db.transaction('notes', 'readwrite')
.objectStore('notes')
.add(note)
await createList()
.then(() => {
textarea.value = ''
dateInput.value = ''
})
} catch { }
}
الآن سنقوم بإنشاء قائمة:let id
const createList = async () => {
list.innerHTML = `<h3>Today is ${new Intl.DateTimeFormat('en', { year: 'numeric', month: 'long', day: 'numeric' }).format()}</h3>`
let notes = await db.transaction('notes')
.objectStore('notes')
.getAll()
let dates = []
if (notes.length) {
id = notes.length
notes.map(note => {
list.insertAdjacentHTML('beforeend',
`<div class = "note" data-id="${note.id}">
//
<span class="notify ${note.notifyDate}">${note.notifyDate}</span>
// ()
// ,
//
//
// (CSS: .info.null, .notify.null)
<span class="info ${note.notifyDate}">?</span>
// ()
<span class="complete">V</span>
//
<p class="${note.completed}">Text: ${note.text}, <br> created: ${note.createdDate}</p>
// ()
<span class="delete">X</span>
</div>`)
if (note.notifyDate === null) {
return
} else {
dates.push({
id: note.id,
date: note.notifyDate.replace(/(\d+)-(\d+)-(\d+)/, '$3.$2.$1')
})
}
})
} else {
id = 0
list.insertAdjacentHTML('beforeend', '<p class="note">empty</p>')
}
تحتوي مجموعة من الكائنات لتخزين تواريخ التذكير على حقلين: "id" لتحديد الملاحظات و "date" لمقارنة التواريخ. عند كتابة قيمة تاريخ التذكير في حقل "التاريخ" ، نضطر إلى تحويل هذه القيمة ، حيث إن inputDate.value تُرجع البيانات بالتنسيق "yyyy-mm-dd" ، وسنقوم بمقارنة هذه البيانات مع البيانات بالصيغة التي اعتدنا عليها ، أي "Dd.mm.yyyy". لذلك ، نستخدم طريقة "استبدال" والتعبير العادي ، حيث باستخدام التجميع ، يتم عكس الكتل واستبدال الواصلات بنقاط. قد يكون هناك حل أكثر تنوعًا أو أناقة.بعد ذلك ، نعمل مع الملاحظات:
document.querySelectorAll('.note').forEach(note => note.addEventListener('click', event => {
if (event.target.classList.contains('complete')) {
event.target.nextElementSibling.classList.toggle('line-through')
note.querySelector('p').classList.contains('line-through')
? notes[note.dataset.id].completed = 'line-through'
: notes[note.dataset.id].completed = ''
db.transaction('notes', 'readwrite')
.objectStore('notes')
.put(notes[note.dataset.id])
} else if (event.target.classList.contains('delete')) {
deleteNote(+note.dataset.id)
} else if (event.target.classList.contains('info')) {
event.target.previousElementSibling.classList.toggle('show')
}
}))
checkDeadline(dates)
}
تبدو وظيفة حذف ملاحظة من القائمة والتخزين كما يلي:const deleteNote = async key => {
await db.transaction('notes', 'readwrite')
.objectStore('notes')
.delete(key)
await createList()
}
لا يمتلك تطبيقنا القدرة على حذف قاعدة البيانات ، ولكن قد تبدو الوظيفة المقابلة كما يلي:document.querySelector('.delete-btn').onclick = async () => {
await idb.deleteDb('dataBase')
.then(location.reload())
}
تقارن وظيفة فحص التذكير التاريخ الحالي وتواريخ التذكير التي أدخلها المستخدم:const checkDeadline = async dates => {
let today = `${new Date().toLocaleDateString()}`
dates.forEach(date => {
if (date.date === today) {
document.querySelector(`div[data-id="${date.id}"] .info`).textContent = '!'
}
})
}
أخيرًا ، أضف معالج الأخطاء إلى كائن Window الذي لم تتم معالجته في كتل التعليمات البرمجية المقابلة:window.addEventListener('unhandledrejection', event => {
console.error('error: ' + event.reason.message)
})
تبدو النتيجة كالتالي:→ Code على Githubهنا تطبيق مشابه على التخزين المحلي:→ كود هذا التطبيق على Githubسأكون سعيدا بأي تعليق.شكرآ لك على أهتمامك.