Membangun Sticky Notes yang Menetap dengan Local Storage
Indonesian (Bahasa Indonesia) translation by Ari Ana (you can also view the original English article)
Penyimpanan lokal HTML5 seperti cookie dengan steroid; ini sangat mudah digunakan namun tetap begitu kuat. Dalam tutorial ini, saya akan menunjukkan cara membuat fungsionalitas "catatan tempel", yang memungkinkan pengguna mengambil catatan yang menetap saat menjelajahi situs Anda.
Langkah 1: HTML
Karena sifat dinamis proyek ini, tidak banyak kode yang bisa dilakukan dalam markup semantik biasa. Kami hanya akan mensimulasikan halaman web dengan menyatukan beberapa konten pengisi:
1 |
<!DOCTYPE html>
|
2 |
<html>
|
3 |
<head>
|
4 |
<meta charset='utf-8' /> |
5 |
<title>HTML 5 complete</title> |
6 |
<link rel="stylesheet" href="default.css" /> |
7 |
<link rel="stylesheet" href="stickies/stickies.css" /> |
8 |
<!--[if IE]>
|
9 |
<script src="https://html5shiv.googlecode.com/svn/trunk/html5.js"></script>
|
10 |
<![endif]-->
|
11 |
</head>
|
12 |
<body>
|
13 |
<article>
|
14 |
<header>
|
15 |
<h1> Sample Article Title</h1> |
16 |
</header>
|
17 |
<p>Lorem ipsum dolor. . . </p> |
18 |
<!-- a few lorem-ipsum paragraphs later . . . -->
|
19 |
<footer>
|
20 |
<p>Copyright 2010 Andrew Burgess</p> |
21 |
</footer>
|
22 |
</article>
|
23 |
|
24 |
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script> |
25 |
<script src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.2/jquery-ui.min.js"></script> |
26 |
<script src="json2.js"></script> |
27 |
<script src="stickies/stickies.js"></script> |
28 |
<script>
|
29 |
</script>
|
30 |
</body>
|
31 |
</html>
|
Ada beberapa hal penting yang perlu diperhatikan di sini: kami menyertakan dua file CSS: yang pertama adalah gaya sederhana untuk halaman, yang telah kami sebut default.css
. Kemudian, kami memiliki file CSS khusus untuk gaya yang terkait dengan catatan tempel kami; ini disebut stickies.css
, dan seperti yang Anda lihat, ia tinggal di folder "stickies". Di bagian bawah, kami menyertakan empat skrip:
- jQuery, dari CDN Google
- JQuery UI, dari CDN Google
- JSON2, dari Douglas Crockford
-
stickies.js
kita sendiri, yang tinggal di direktori "stickies"
Kemudian, kami memiliki tag script kosong yang akan kami gunakan untuk menghidupkan mesin sedikit kemudian.
Dan itu untuk HTML!
Langkah 2: CSS
Konten default.css
sangat sederhana:
1 |
body { |
2 |
margin:0; |
3 |
padding:0; |
4 |
background:#ccc; |
5 |
font:14px/1.5 "Helvetica Neue", Helvetica, Arial, san-serif; |
6 |
}
|
7 |
article, footer, header { display: block; } |
8 |
article { |
9 |
width:880px; |
10 |
background:#fff; |
11 |
margin:auto; |
12 |
padding:40px; |
13 |
}
|
14 |
article header { |
15 |
color:#474747; |
16 |
border-bottom:1px solid #474747 |
17 |
}
|
18 |
article footer { |
19 |
font-size:90%; |
20 |
color:#ccc; |
21 |
}
|
Itu saja; sekarang, ada CSS dari stickies.css
untuk dijaga... tapi kita belum memiliki markup itu. Jadi mari kita mulai beberapa JavaScript, dan setelah selesai, kita akan melihat CSS untuk catatan tempel.
Langkah 3: JavaScript
Inilah kerangka untuk aplikasi JavaScript kita:
1 |
var STICKIES = (function () { |
2 |
var initStickies = function () {}, |
3 |
openStickies = function () {}, |
4 |
createSticky = function (data) {}, |
5 |
deleteSticky = function (id) {}, |
6 |
saveSticky = function () {}, |
7 |
markUnsaved = function () {}; |
8 |
|
9 |
return { |
10 |
open : openStickies, |
11 |
init : initStickies |
12 |
};
|
13 |
}());
|
Kita punya beberapa teknik menarik yang terjadi di sini. Pertama adalah fungsi yang memanggil dirinya sendiri: mungkin terlihat seperti kita menugaskan fungsi ke variabel STICKIES
, tapi jika Anda melihat dari dekat fungsi ini, Anda akan melihat bahwa kita menjalankannya dengan segera. Sebagai petunjuk—untuk mengingatkan kita bahwa ini bukan fungsi normal—kita membungkus keseluruhan fungsi dalam tanda kurung. Jadi, STICKIES
bukanlah fungsi, itu adalah nilai yang dikembalikan dari fungsi itu, yang merupakan objek, dalam kasus ini.
Itu membawa kita ke teknik berikutnya: penutupan. Perhatikan bahwa dari enam fungsi yang kita buat, hanya dua di antaranya yang terpapar pada pengguna (sebenarnya hanya satu yang diperlukan untuk penggunaan yang kami rencanakan; jika kita ingin membangun dukungan untuk membuat catatan ke situs web Anda, kita dapat mengekspos createSticky
dan deleteSticky
). Meskipun fungsi yang memanggil dirinya sendiri selesai dijalankan sebelum kita menggunakan metode ini, kita akan dapat menggunakan fungsi lain yang telah kita definisikan.
Oke, mari beralih ke isi dari fungsi ini.
initStickies
Kita akan mulai dengan melihat fungsi initStickies
:
1 |
var initStickies = function initStickies() { |
2 |
$("<div />", { |
3 |
text : "+", |
4 |
"class" : "add-sticky", |
5 |
click : function () { createSticky(); } |
6 |
}).prependTo(document.body); |
7 |
initStickies = null; |
8 |
},
|
Ini sangat sederhana. Kita akan menggunakan jQuery dengan cukup sedikit untuk membuat elemen, dan kita menggunakan beberapa sintaks khusus dalam v. 1.4: yang mengirimkan sebuah objek literal dengan spesifikasi elemen sebagai parameter kedua pada fungsi jQuery. Di sini, kita menciptakan sebuah tombol untuk membuat catatan baru. Itu berarti kita membutuhkan div
baru; kita menetapkan teksnya ke "+" dan memberinya kelas "add-sticky"; kemudian, kita menetapkan handler klik untuk memanggil metode createSticky
(penting untuk memanggil createSticky
dari dalam sebuah fungsi, dan tidak ada handler klik yang langsung memanggil createSticky
; ini karena createSticky
dapat mengambil satu parameter saja, dan kita tidak ingin itu menjadi objek event). Akhirnya, kita menambahkan div
ini ke body. Kita akhiri dengan mengatur initStickies
menjadi null
; ya, pada dasarnya kita menyingkirkan fungsi yang kita jalankan. Ini meyakinkan kita bahwa fungsi ini hanya akan dijalankan sekali; kami tidak ingin pengguna API kami secara tidak sengaja menambahkan beberapa tombol "add note" ke halaman.
openStickies
Mari beralih ke metode selanjutnya, openStickies
:
1 |
openStickies = function openStickies() { |
2 |
initStickies && initStickies(); |
3 |
for (var i = 0; i < localStorage.length; i++) { |
4 |
createSticky(JSON.parse(localStorage.getItem(localStorage.key(i)))); |
5 |
}
|
6 |
},
|
Kita mulai dengan menjalankan initStickies
... tapi ada apa dengan sintaksnya? Nah, Anda mungkin akrab dengan operator &&
: operator AND boolean. Anda biasanya menggunakannya untuk memeriksa beberapa kondisi dalam pernyataan if. Inilah yang sebenarnya terjadi: ia mengevaluasi ekspresi pertama, dan jika itu true, ia akan terus mengevaluasi ekspresi kedua. Dalam kasus ini, jika initStickies
belum diset ke null, kita akan menjalankan fungsinya. Hal ini untuk menghindari kesalahan yang akan datang dari mencoba menjalankan variabel null sebagai fungsi.
Selanjutnya, kita mengulangi setiap item di localStorage. Inilah yang kami lakukan dalam for-loop itu (dari dalam ke luar):
-
localStorage.key()
adalah fungsi hebat yang mengembalikan nama kunci dari nilailocalStorage
; dibutuhkan angka sebagai parameter. Ini adalah cara yang bagus untuk mengulang setiap item dilocalStorage
. - Begitu kita memiliki kunci untuk barang yang tersimpan, kita bisa mengirimkannya ke
localStorage.getItem()
untuk mendapatkan nilainya. - Kemudian, kita menyampaikan nilai itu ke
JSON.parse()
; ini berasal dari perpustakaan Crockford. Karena kita menyimpan beberapa nilai untuk setiap catatan, kita menggunakanJSON.stringify()
di ujung yang lain untuk mengubah objek menjadi string JSON, yang kita simpan. Di sini, kita mengubahnya dari string kembali menjadi objek. - Akhirnya, kita mengirimkan objek itu ke
createSticky()
, yang mengubahnya menjadi catatan tempel.
createSticky
Sekarang, mari kita lihat metode createSticky
itu.
1 |
createSticky = function createSticky(data) { |
2 |
data = data || { id : +new Date(), top : "40px", left : "40px", text : "Note Here" } |
3 |
|
4 |
return $("<div />", { |
5 |
"class" : "sticky", |
6 |
'id' : data.id |
7 |
})
|
8 |
.prepend($("<div />", { "class" : "sticky-header"} ) |
9 |
.append($("<span />", { |
10 |
"class" : "status-sticky", |
11 |
click : saveSticky |
12 |
}))
|
13 |
.append($("<span />", { |
14 |
"class" : "close-sticky", |
15 |
text : "trash", |
16 |
click : function () { deleteSticky($(this).parents(".sticky").attr("id")); } |
17 |
}))
|
18 |
)
|
19 |
.append($("<div />", { |
20 |
html : data.text, |
21 |
contentEditable : true, |
22 |
"class" : "sticky-content", |
23 |
keypress : markUnsaved |
24 |
}))
|
25 |
.draggable({ |
26 |
handle : "div.sticky-header", |
27 |
stack : ".sticky", |
28 |
start : markUnsaved, |
29 |
stop : saveSticky |
30 |
})
|
31 |
.css({ |
32 |
position: "absolute", |
33 |
"top" : data.top, |
34 |
"left": data.left |
35 |
})
|
36 |
.focusout(saveSticky) |
37 |
.appendTo(document.body); |
38 |
},
|
Ya, sudah lama, tapi tidak akan terlalu sulit. Pertama, perhatikan bahwa fungsi ini mengambil objek data; seperti yang baru saja kita lihat di openStickies
, kita meneruskan data yang tersimpan ke fungsi ini. Namun, jika kami tidak menyampaikan data apa pun (yaitu, kami membuat catatan baru), kami akan membuat objek catatan default. Karena semua catatan harus dibuat pada satu titik, semua catatan akan dimulai dengan konfigurasi ini. Perhatikan bahwa untuk id catatan, kami menggunakan +new Date()
; yang ditambah operator plus unary yang mengubah tanggal yang kami dapatkan dari tanggal baru ke angka, jadi pernyataan ini menghasilkan angka yang mewakili jumlah milidetik sejak 1 Januari 1970. Jelas, nomor ini akan terus berubah, jadi ini adalah cara yang bagus untuk mengidentifikasi setiap catatan secara unik.
Sisa dari fungsi adalah string panjang metode berantai jQuery. Sebelum kita melalui ini, perhatikan bahwa kita mengembalikan hasilnya. Jika kita mengekspos metode ini kepada pengembang menggunakan mirco-API kita, itu akan mengembalikan referensi ke elemen div catatan tempel.
Jadi, inilah yang terjadi:
-
Pertama, kita membuat
div
yang merupakan tempurung dari catatan tempel. Dengan menggunakan sintaks jQuery 1.4 yang bermanfaat, kami memberikan kelas "sticky" dan id dari objek data. -
Kemudian, kita menambahkan
div
ke sana;div
ini mendapat kelas "sticky-header".div.sticky-header
kemudian mendapat dua span ditambahkan ke sana. Yang pertama,span.sticky-status
, mendapat handler klik yang memanggil fungsisaveSticky
. Namun, itu sebenarnya fitur tersembunyi: span ini akan menampilkan status yang sticky: tersimpan atau belum disimpan. Akan ada beberapa cara sticky menyimpan datanya kelocalStorage
; mungkin pengguna akan berpikir bahwa mengklik 'unsaved' akan menyimpan catatan, jadi kami akan memberi mereka fungsi itu. Span kedua,span.close-sticky
, akan menjadi tombol hapus: saat pengguna mengkliknya, kami akan menghapus sticky darilocalStorage
, melalui metodedeleteSticky
. Kami melewatkan metode itu id catatan. -
Selanjutnya, kita menambahkan div lain ke
div.sticky
utama; perhatikan bahwa kita mengatur propertihtml
kedata.text
; saat kita menyimpan teks catatan, kita menggunakan metodehtml()
dari jQuery, karena menggunakantext()
menghilangkan jeda baris. Kita juga mengaturcontentEditable:true
di div ini, karena ini adalah isi dari catatan. Dengan demikian, itu juga mendapat kelassticky-content
. Akhirnya, ketika tombol ditekan pada div ini (artinya pengguna mengubah konten), kami ingin menandainya sebagai tidak tersimpan, jadi kita akan memanggil fungsi itu (yang akan segera kita lakukan). -
Sekarang, kami menggunakan fitur jQuery UI draggable untuk membuat catatan tempel kita dapat dipindah-pindahkan. Di objek parameter kita, kita menggunakan properti
handle
agar catatan kita hanya dapat dipindahkan dari bilah header. Propertistack
adalah pemilih untuk elemen yang dapat diseret yang ingin di-"stack"; dengan pengaturan ini, catatan yang saat ini terseret akan selalu berada di atas. Akhirnya, ketika kita mulai menyeret catatan, kita ingin menandainya sebagai "belum disimpan" (karena kita juga harus menyimpan koordinatnya), dan ketika kita berhenti menyeret, kita akan menyimpan sticky itu. -
Selanjutnya, kita menetapkan beberapa gaya untuk
div.sticky
kita; kita memposisikannya secara absolute, dan kemudian menetapkan nilai atas dan kiri ke nilai pada objek data. Dengan cara ini, catatan akan tetap mempertahankan posisinya dan juga isinya saat kita me-refresh halaman. -
Akhirnya, kita akan mengatur event handler saat kita
focusout
sticky (intinya, klik di luarnya setelah mengkliknya): kita ingin menyimpan sticky. Terakhir, kami akan menambahkannya ke body. Sebagai rujukan, inilah struktur html yang seharusnya kita hasilkan:
1 |
<div class="sticky ui-draggable" id="1281194825332" style="position: absolute; top: 40px; left: 40px;"> |
2 |
<div class="sticky-header"> |
3 |
<span class="sticky-status"></span> |
4 |
<span class="close-sticky">trash</span> |
5 |
</div>
|
6 |
<div contenteditable="true" class="sticky-content"> |
7 |
Note Here |
8 |
</div>
|
9 |
</div>
|
Dan itulah fungsi createSticky
kita.
deleteSticky
Sekarang kita memiliki fungsi deleteSticky
; ini sangat sederhana:
1 |
deleteSticky = function deleteSticky(id) { |
2 |
localStorage.removeItem("sticky-" + id); |
3 |
$("#" + id).fadeOut(200, function () { $(this).remove(); }); |
4 |
},
|
Seperti yang Anda ingat, fungsi deleteSticky
mengambil id dari sebuah catatan sebagai parameternya. localStorage.removeItem()
adalah metode jamnya: kita menyampaikan ke nilai yang tersimpan secara lokal untuk menghapus pasangan kunci-nilai tersebut (Perhatikan bahwa ketika kita menyimpan data catatan, kita menambahkan "sticky-" ke id). Kemudian, kita menemukan elemen dengan id yang diberikan, memudarkannya, dan menghapusnya. Catatan dihapus!
saveSticky
Kedua-sampai-terakhir mungkin metode yang paling penting hari ini: saveSticky
: ini adalah lem yang membuat semuanya bekerja.
1 |
saveSticky = function saveSticky() { |
2 |
var that = $(this), sticky = (that.hasClass("sticky-status") || that.hasClass("sticky-content")) ? that.parents('div.sticky'): that, |
3 |
obj = { |
4 |
id : sticky.attr("id"), |
5 |
top : sticky.css("top"), |
6 |
left: sticky.css("left"), |
7 |
text: sticky.children(".sticky-content").html() |
8 |
}
|
9 |
localStorage.setItem("sticky-" + obj.id, JSON.stringify(obj)); |
10 |
sticky.find(".sticky-status").text("saved"); |
11 |
},
|
Baris pertama adalah sedikit resolusi: ada tiga elemen yang berbeda yang bisa kita panggil fungsi ini darinya. Pertama, kita akan "men-jQuery-kan" this
ke that
; jika elemennya memiliki kelas "sticky-status" atau "sticky-content", kita akan mendapatkan induk div.sticky
; jika tidak memiliki salah satu dari kelas tersebut, maka itu adalah div.sticky
itu sendiri, jadi kita akan langsung menggunakannya.
Kemudian, kita perlu mendapatkan nilai yang ingin kita simpan. Seperti yang bisa Anda lihat, kita mendapatkan id, offset dari atas dan kiri, dan html dari anak .sticky-content
; ingat, kita menggunakan html()
bukannya text()
karena kita ingin menyimpan jeda baris. Kemudian, kita menggunakan localStorage.setItem
untuk menyimpan datanya. Ingat, dibutuhkan dua parameter: kunci dan nilai untuk disimpan. Karena localStorage
hanya menyimpan string, kita menggunakan JSON.stringify()
untuk mengubah objek menjadi string.
Terakhir, mengubah status sticky menjadi "saved."
markUnsaved
Kita punya satu fungsi terakhir, yang hanya fungsi helper:
1 |
markUnsaved = function markUnsaved() { |
2 |
var that = $(this), sticky = that.hasClass("sticky-content") ? that.parents("div.sticky") : that; |
3 |
sticky.find(".sticky-status").text("unsaved"); |
4 |
}
|
Sekali lagi, kita harus mulai dengan menyelesaikan referensi ke div.sticky
; begitu kita melakukannya, kita bisa menemukan span status dan mengatur teksnya menjadi "unsaved."
Percaya atau tidak, itu saja JavaScript-nya.
Langkah 4: CSS, Kunjungan Ulang
Sekarang kita tahu apa markup catatan tempel kita, kita bisa memberinya gaya. Ini sangat sederhana; tapi lihat saja, dan saya akan membuat beberapa komentar di akhir:
1 |
:focus { |
2 |
outline:0; |
3 |
}
|
4 |
.add-sticky { |
5 |
cursor: default; |
6 |
position:absolute; |
7 |
top:1px; |
8 |
left:1px; |
9 |
font-size:200%; |
10 |
background:#000; |
11 |
color:#fff; |
12 |
border:2px solid #fff; |
13 |
border-radius:40px; |
14 |
-webkit-border-radius:40px; |
15 |
-moz-border-radius:40px; |
16 |
text-align:center; |
17 |
line-height:25px; |
18 |
width:30px; |
19 |
height:30px; |
20 |
}
|
21 |
.add-sticky:hover { |
22 |
background: #474747; |
23 |
}
|
24 |
.sticky { |
25 |
width:300px; |
26 |
background:#fdfdbe; |
27 |
box-shadow:3px 3px 10px rgba(0,0,0,0.45); |
28 |
-webkit-box-shadow:3px 3px 10px rgba(0,0,0,0.45); |
29 |
-moz-box-shadow:3px 3px 10px rgba(0,0,0,0.45); |
30 |
}
|
31 |
.sticky-content { |
32 |
min-height:150px; |
33 |
border-left:3px double rgba(238, 150, 122, .75); |
34 |
margin-left:30px; |
35 |
padding:5px; |
36 |
}
|
37 |
.sticky-header { |
38 |
padding:5px; |
39 |
background:#f3f3f3; |
40 |
border-bottom:2px solid #fefefe; |
41 |
box-shadow:0 3px 5px rgba(0,0,0,0.25); |
42 |
-webkit-box-shadow:0 3px 5px rgba(0,0,0,0.25); |
43 |
-moz-box-shadow:0 3px 5px rgba(0,0,0,0.25); |
44 |
}
|
45 |
.sticky-status { |
46 |
color:#ccc; |
47 |
padding:5px; |
48 |
}
|
49 |
.close-sticky { |
50 |
background:#474747; |
51 |
float:right; |
52 |
cursor:default; |
53 |
color:#ececec; |
54 |
padding:1px 5px; |
55 |
border-radius:20px; |
56 |
-webkit-border-radius:20px; |
57 |
-moz-border-radius:20px; |
58 |
}
|
Ada beberapa hal menarik di sini:
- Beberapa browser menempatkan garis tepi di seputar elemen dengan
contenteditable=true
saat Anda mengedit konten. Kita tidak menginginkan itu, jadi kita menyingkirkannya dengan deklarasi:focus
kita. - Tombol "Add Sticky" diposisikan di sudut kiri atas; tampilannya samar-samar mirip dengan "Add Dashboard Widget" di Mac OS X.
- Kita menggunakan properti CSS3 border-radius dan box-shadow (dan inkarnasi prefiks vendor yang sesuai).
- Kami juga menggunakan
rgba()
untuk warna bayangan kami. Dibutuhkan empat parameter: warna merah, hijau, dan biru, dan nilai alpha (transparansi).
Selain itu, itu hanya CSS standar Anda. Seperti inilah tampilan catatan yang diberi gaya:

Langkah 5: Memulai Stickies
Sekarang setelah kita membuat API kita, saatnya memulainya; kita bisa melakukan itu dari tag script
tambahan kosong di file index.html
kita:
1 |
STICKIES.open(); |
Kesimpulan: Produk Akhir
Kita sudah selesai! Inilah produk akhir yang beraksi:
Hanya itu yang saya miliki hari ini; bagaimana Anda berencana untuk menggunakan penyimpanan lokal HTML5 untuk membumbui proyek web Anda? Beri tahu saya di komentar!