Artikel pertama tentang
dap , jelas, tidak menjadi kesuksesan tulisan saya: sebagian besar komentar mengenai hal itu bermuara pada "niasilil" dan "niasilil, tetapi saya mengutuk." Dan hadiah untuk satu
- satunya komentar tingkat atas yang konstruktif diberikan kepada
OldVitus , untuk saran untuk menunjukkan yang dap menggunakan TodoMVC sebagai contoh, sehingga ada sesuatu yang bisa dibandingkan. Apa yang akan saya lakukan di artikel ini.
TodoMVC , jika ada yang tidak tahu, ini adalah dunia panggilan-UI standar, yang memungkinkan Anda untuk membandingkan solusi untuk masalah yang sama - "daftar tugas" bersyarat - menggunakan kerangka kerja yang berbeda. Tugas, dengan semua kesederhanaannya (
solusi pada dap break "dalam satu layar"), sangat ilustratif. Oleh karena itu, dengan menggunakan contohnya, saya akan mencoba menunjukkan bagaimana tugas-tugas khas untuk web front-end diimplementasikan menggunakan dap.
Saya tidak mencari dan mempelajari deskripsi formal masalah, tetapi memutuskan untuk membalik salah satu contoh. Backend untuk artikel ini tidak menarik bagi kami, jadi kami tidak akan menulisnya sendiri, tetapi gunakan
salah satu yang sudah jadi dari situs
www.todobackend.com , dan dari sana kami akan mengambil
contoh klien dan
file CSS standar.
Untuk menggunakan dap, Anda tidak perlu mengunduh dan menginstal apa pun. Tidak ada
npm install
dan itu saja. Tidak diperlukan untuk membuat proyek apa pun dengan struktur direktori tertentu, manifesto, dan atribut keberhasilan TI lainnya. Editor dan peramban teks yang cukup. Untuk men-debug permintaan XHR, Anda juga mungkin memerlukan server web - yang cukup sederhana, seperti
ekstensi untuk Chrome ini. Seluruh frontend kami akan terdiri dari satu file .html (tentu saja, mengacu pada skrip engine-dap dan ke file CSS TodoMVC standar)
Jadi, dari awal.
1. Buat file .html
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Todo -- dap sample</title> <link rel="stylesheet" href="https://www.todobackend.com/client/css/vendor/todomvc-common.css"/> <script src="https://dap.js.org/0.4.js"></script> </head> <body> <script> </script> </body> </html>
Persiapan html biasa di mana kami menyertakan file-CSS, silakan disediakan oleh situs
www.todobackend.com dan mesin-dap, tidak kalah ramah disediakan oleh situs
dap.js.org2. Salin struktur DOM dari contoh aslinya
Untuk menggunakan file CSS standar tanpa perubahan, kami akan mematuhi struktur DOM yang sama dengan
contoh aslinya . Buka di browser Chrome, tekan Ctr + Shift + I, pilih tab Elements dan lihat bahwa aplikasi itu sendiri ada di bagian elemen
section id="todo-app">

Dengan membuka subtree ini satu per satu, kami menulis ulang strukturnya menjadi file .html kami. Sekarang kita hanya membuat sketsa dengan cepat, dan tidak menulis kode, jadi kita hanya menulis tanda tangan elemen dalam 'tanda kutip tunggal', dan dalam tanda kurung anak-anak mereka. Jika tidak ada anak, kami menggambar tanda kurung kosong. Kami memantau indeks dan keseimbangan kurung.
Catatan: elemen berulang (misalnya, ini adalah elemen
LI
) kami menulis ke struktur sekali, bahkan jika ada beberapa di antaranya dalam aslinya; jelas ini adalah array dari pola yang sama.
Format tanda tangan, saya pikir, dapat dimengerti oleh siapa saja yang menulis HTML dan CSS dengan tangan mereka, jadi saya tidak akan membahasnya secara rinci untuk saat ini. Saya hanya bisa mengatakan bahwa tag ditulis dalam huruf kapital, dan tidak adanya tag setara dengan keberadaan tag DIV. Kelimpahan # -elements (dengan id) di sini disebabkan oleh spesifikasi file CSS yang disertakan, yang terutama menggunakan pemilih-id.
3. Ingat bahwa program dap adalah Javascript
Untuk menyelamatkan kami dari tanda kurung yang tidak perlu dalam kode, mesin dap menyuntikkan beberapa metode langsung ke
String.prototype
(Saya menyadari bahwa menerapkan metode Anda di objek standar adalah ayahay, tapi ... singkatnya, kami telah lulus), yang mengubah string tanda tangan menjadi dap templat. Salah satu metode tersebut adalah
.d(rule, ...children)
. Argumen pertama yang dibutuhkan adalah aturan generasi (
d-rule ), dan sisanya dari argumen adalah jumlah anak yang sewenang-wenang.
Berdasarkan pengetahuan baru ini, kami menambahkan kode kami sehingga alih-alih setiap brace pembuka, kami memiliki urutan
.d(""
, dan sebelum setiap kutipan tunggal dibuka, kecuali yang pertama, ada koma. Life hack: Anda dapat menggunakan penggantian otomatis.
'#todoapp'.d("" ,'#header'.d("" ,'H1'.d("") ,'INPUT#new-todo placeholder="What needs to be done?" autofocus'.d("") ) ,'#main'.d("" ,'#toggle-all type=checkbox'.d("") ,'UL#todo-list'.d("" ,'LI'.d("" ,'INPUT.toggle type=checkbox'.d("") ,'LABEL'.d("") ,'BUTTON.destroy'.d("") ) ) ) ,'#footer'.d("" ,'#todo-count'.d("") ,'UL#filters'.d("" ,'LI'.d("") ) ,'#clear-completed'.d("") ) )
Voila! Kami mendapat pohon panggilan ke metode
.d
, yang siap untuk berubah menjadi template dap. String kosong
""
adalah benih aturan-d di masa depan, dan anak-anak adalah argumen yang dipisahkan oleh koma. Secara formal, ini adalah program dap yang valid, meski belum sepenuhnya dengan knalpot yang kita butuhkan. Tapi itu sudah bisa diluncurkan! Untuk melakukan ini, setelah braket root penutup, tambahkan metode
.RENDER()
. Metode ini, seperti namanya, membuat templat yang dihasilkan.
Jadi, pada tahap ini, kami memiliki file .html dengan konten ini:
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Todo -- dap sample</title> <link rel="stylesheet" href="https://www.todobackend.com/client/css/vendor/todomvc-common.css"/> <script src="https://dap.js.org/0.4.js"></script> </head> <body> <script> '#todoapp'.d("" ,'#header'.d("" ,'H1'.d("") ,'INPUT#new-todo placeholder="What needs to be done?" autofocus'.d("") ) ,'#main'.d("" ,'#toggle-all type=checkbox'.d("") ,'UL#todo-list'.d("" ,'LI'.d("" ,'INPUT.toggle type=checkbox'.d("") ,'LABEL'.d("") ,'BUTTON.destroy'.d("") ) ) ) ,'#footer'.d("" ,'#todo-count'.d("") ,'UL#filters'.d("" ,'LI'.d("") ) ,'#clear-completed'.d("") ) ) .RENDER() // dap </script> </body> </html>
Anda dapat
membukanya di browser untuk memastikan bahwa elemen DOM dihasilkan, gaya CSS diterapkan, tetap hanya untuk mengisi templat ini dengan data.
4. Dapatkan data
Kami pergi ke
halaman asli , buka tab Network di alat, aktifkan filter XHR, dan lihat dari mana data berasal dan dalam bentuk apa.


Baik, baik. Daftar yang harus dilakukan diambil langsung dari
todo-backend-express.herokuapp.com sebagai json array objek. Bagus
Untuk menerima data, dap memiliki konverter bawaan
:query
yang secara asinkron "mengubah" URL menjadi data yang diterima darinya. Kami tidak akan menulis URL itu sendiri secara langsung dalam aturan, tetapi kami akan menetapkannya dengan
todos
konstan; maka seluruh desain data mining akan terlihat seperti ini:
todos:query
dan tulis konstanta
todos
itu sendiri di kamus - di bagian
.DICT
, tepat sebelum
.RENDER()
:
'#todoapp'.d("" ... ) .DICT({ todos : "https://todo-backend-express.herokuapp.com/" }) .RENDER()
Setelah menerima array
todos
, kami membuat daftar tugas dari itu: untuk setiap kasus kami mengambil nama dari bidang
.title
dan menulisnya ke elemen
LABEL
, dan dari bidang
.completed
mengambil tanda "kelengkapan" dan menulis ke properti yang
checked
dari
checked
elemen
INPUT.toggle
. Ini dilakukan seperti ini:
,'UL#todo-list'.d("*@ todos:query"
Kami memperbarui halaman kami di browser dan ... jika Anda memulainya dari sistem file, maka tidak ada yang terjadi. Masalahnya adalah browser modern tidak mengizinkan permintaan XHR lintas-domain dari dokumen lokal.

Saatnya menonton laman kami melalui http - menggunakan server web lokal apa pun. Baik, atau jika Anda tidak siap untuk menulis dap dengan tangan Anda sendiri, lihat versi berurutan halaman menggunakan tautan saya (jangan lupa untuk melihat sumbernya - di Chrome ini dilakukan dengan menggunakan Ctrl + U)
Jadi, kita
pergi ke halaman kita di http: // dan melihat bahwa datanya datang, daftar sedang dibangun. Hebat! Anda telah menguasai
*
dan operator
!
, konverter
:query
, konstanta dan akses ke bidang elemen array saat ini. Lihat lagi kode yang dihasilkan. Apakah Anda masih merasa tidak dapat membaca?
5. Tambahkan status
Mungkin Anda sudah mencoba mengklik tanda centang di daftar yang harus dilakukan. Kotak centang itu sendiri berubah warna, tetapi, tidak seperti aslinya, elemen induk
LI
tidak mengubah gayanya ("pekerjaan yang diselesaikan" harus menjadi abu-abu dan dicoret, tetapi ini tidak terjadi) - hal-hal tidak mengubah
keadaan mereka. Tetapi elemen-elemen ini belum memiliki keadaan dan, karenanya, tidak dapat mengubahnya. Sekarang kita akan memperbaikinya.
Tambahkan status "selesai" ke elemen
LI
. Untuk melakukan ini, tentukan
variabel state $completed
completion dalam d-rule-nya. Untuk
INPUT.toggle
, yang dapat mengubah status ini, kami akan menetapkan aturan reaksi yang sesuai (
ui-rule ), yang akan mengatur variabel
$completed
sesuai dengan tanda bendernya sendiri yang
checked
(“daw diaktifkan”). Bergantung pada status
$completed
elemen
LI
akan mengaktifkan atau menonaktifkan kelas CSS "selesai".
,'UL#todo-list'.d("*@ todos:query" ,'LI'.d("$completed=.completed"
Manipulasi seperti ini dengan kelas CSS adalah hal yang cukup umum, jadi ada operator khusus untuk mereka !?
Harap dicatat bahwa kami melakukan ini di
a-rule (dari kata akumulasi). Kenapa tidak di d-rule? Perbedaan antara kedua jenis aturan ini adalah ketika memperbarui, aturan-d sepenuhnya membangun kembali konten elemen, menghapus yang lama dan yang baru lagi, sedangkan aturan-a tidak menyentuh konten elemen yang ada, tetapi "menambahkan" hasilnya pada apa yang sudah ada. Mengubah atribut tunggal elemen
LI
tidak memerlukan restrukturisasi sisa isinya, sehingga lebih rasional untuk melakukan ini dalam aturan-a.
Kami melihat
hasilnya . Sudah lebih baik: mengklik pada kotak centang mengubah keadaan item yang harus dilakukan, dan sesuai dengan keadaan ini, gaya visual elemen berubah. Tetapi masih ada masalah: jika daftar tugas yang diselesaikan pada awalnya hadir, mereka tidak akan berwarna abu-abu, karena secara default a-rule tidak dieksekusi ketika elemen dihasilkan. Untuk menjalankannya bahkan selama pembangkitan, kita menambahkan operator
a!
Pada aturan-d dari elemen
LI
,'LI'.d("$completed=.completed; a!"
Kami melihat . Baiklah Dengan status
$completed
tahu. Kasing yang telah selesai distilisasi dengan benar, baik pada saat boot awal maupun selama perpindahan manual berikutnya.
6. Mengedit nama kasus
Kembali ke
aslinya . Dengan mengklik dua kali pada nama case, mode pengeditan diaktifkan, di mana nama ini dapat diubah. Itu diimplementasikan sedemikian rupa sehingga templat mode tampilan “view” (dengan daw, judul dan tombol hapus) sepenuhnya tersembunyi, dan elemen
INPUT class="edit"
ditampilkan. Kami akan melakukannya sedikit berbeda - kami hanya akan menyembunyikan elemen
LABEL
, karena dua elemen lainnya tidak mengganggu pengeditan kami. Cukup tambahkan kelas
view
ke elemen
LABEL
.
Untuk kondisi "editing", tentukan variabel
$editing
dalam elemen
LI
. Awalnya, ini (keadaan) diatur ulang,
dblclick
dengan
dblclick
pada elemen
LABEL
, dan mati ketika elemen
INPUT.edit
tidak fokus. Jadi kami menulis:
,'LI'.d("$completed=.completed $editing=; a!"
Sekarang kita
bisa mengedit nama-nama kasing.
7. Mengirim data ke server
Oke, kita sudah bisa mengedit hal-hal di browser, tetapi perubahan ini juga harus ditransfer ke server. Kami melihat bagaimana yang asli melakukannya:

Perubahan dikirim ke server menggunakan metode PATCH dengan URL tertentu dari formulir
http://todo-backend-express.herokuapp.com/28185
, yang, jelas, unik untuk setiap kasus. URL ini ditunjukkan oleh server di bidang
.url
untuk setiap kasus dalam daftar. Artinya, semua yang diperlukan dari kami untuk memperbarui kasus di server adalah mengirim permintaan PATCH ke alamat yang ditentukan dalam bidang
.url
, dengan data yang diubah dalam format JSON:
,'INPUT.edit' .d("? $editing; !! .title@value") .ui(".title=#.value; (@method`PATCH .url (@Content-type`application/json)@headers (.title):json.encode@body):query") .e("blur","$editing=")
Di sini kami menggunakan konverter yang sama
:query
, tetapi dalam versi yang lebih rinci. Ketika
:query
diterapkan ke string sederhana, string ini diperlakukan sebagai URL dan permintaan GET dijalankan. Jika
:query
menerima objek yang kompleks, seperti dalam kasus ini,
:query
memperlakukannya sebagai deskripsi terperinci dari permintaan yang berisi bidang
.method
,
.url
,
.headers
, dan
.body
, dan menjalankan permintaan sesuai dengan mereka. Di sini, segera setelah memperbarui
.title
mengirim permintaan PATCH ke server dengan
.title
diperbarui ini
Namun ada nuansa. Kami mendapatkan bidang
.url
dari server, tampilannya seperti ini:
http://todo-backend-express.herokuapp.com/28185
, yaitu protokol http: // hardcode di dalamnya jika klien kami juga membuka melalui http: // maka semuanya baik-baik saja. Tetapi jika klien terbuka melalui https: //, maka muncul masalah: untuk alasan keamanan, browser memblokir http-traffic dari sumber https.
Itu dipecahkan secara sederhana: jika Anda menghapus protokol dari
.url
, permintaan akan melewati protokol halaman. Jadi mari kita lakukan: tulis konverter yang sesuai -
dehttp
, dan kita akan melewati
.url
melaluinya. Konverter khusus (dan fungsi lainnya)
.FUNC
di bagian
.FUNC
:
.ui(".title=#.value; (@method`PATCH .url:dehttp (@Content-type`application/json)@headers (.title):json.encode@body):query") ... .FUNC({ convert:{
Masuk akal juga untuk menempatkan objek header di kamus sehingga dapat digunakan di pertanyaan lain:
.ui(".title=#.value; (@method`PATCH .url:dehttp headers (.title):json.encode@body):query") ... .DICT({ todos : "//todo-backend-express.herokuapp.com/", headers: {"Content-type":"application/json"} })
Nah, untuk feng shui penuh, kita akan menggunakan properti lain yang berguna dari konverter
:query
- pengkodean otomatis dari tubuh permintaan di json sesuai dengan
Content-type:application/json
header. Akibatnya, aturannya akan terlihat seperti ini:
.ui(".title=#.value; (@method`PATCH .url:dehttp headers (.title)):query")
Jadi,
lihat . Oke, nama case sekarang berubah tidak hanya di browser, tetapi juga di server. Tapi! Tidak hanya nama kasus dapat berubah, tetapi juga status penyelesaiannya -
completed
. Jadi, itu juga perlu dikirim ke server.
Anda dapat menambahkan permintaan PATCH yang sama ke elemen
INPUT.toggle
, cukup kirim
(.completed)
alih-alih
(.completed)
:
,'INPUT.toggle type=checkbox' .d("#.checked=.completed") .ui("$completed=#.checked; (@method`PATCH .url:dehttp headers (.completed:?)):query")
Dan Anda dapat menempatkan permintaan PATCH ini "out of brackets":
,'LI'.d("$completed=.completed $editing= $patch=; a!"
Ini masalahnya. Aturan reaksi termasuk dalam kelompok "aturan atas", yang dieksekusi "dari bawah ke atas" - dari turunan ke induk, ke akar itu sendiri (urutan ini dapat diinterupsi jika perlu). Ini agak seperti acara pop-up di DOM. Oleh karena itu, beberapa fragmen dari reaksi umum terhadap beberapa keturunan dapat diberikan kepada leluhur yang sama.
Secara khusus, dalam kasus kami, keuntungan dari delegasi tersebut tidak terlalu terlihat, tetapi jika ada lebih banyak bidang yang dapat diedit, maka menempatkan permintaan besar ini (berdasarkan standar, tentu saja) ke dalam satu aturan umum akan sangat membantu menjaga kode tetap sederhana dan mudah dibaca. Jadi saya merekomendasikannya.
Kami melihat : Sekarang perubahan nama dan perubahan status dikirim ke server.
Di artikel selanjutnya, jika Anda tertarik, pertimbangkan untuk menambah, menghapus, dan memfilter kasing. Sementara itu, Anda dapat melihat
hasil akhir dan contoh kode dap lainnya di
dap.js.org/docs