Apakah desainer punya ide baru? Apa yang bisa lebih mudah

Halo, habrovchanin! Desainer adalah orang-orang ideologis, dan pelanggan, terutama dengan persyaratan bisnis mereka.

Bayangkan bahwa Anda telah menumpuk UIkit terbaik Anda di dunia pada%% paling keren masukkan kerangka% JS Anda. Tampaknya ada segala yang dibutuhkan proyek. Sekarang Anda dapat minum kopi, dan menutup semua tugas baru dengan melemparkan komponen pada halaman. Bahkan lebih baik, jika Anda menemukan UIkit seperti itu di tempat sampah di NPM ruang terbuka dan sangat cocok dengan UX / UI saat ini dan kebutuhannya. Fiksi!

Dan sungguh ... siapa aku bercanda? Kebahagiaan Anda cenderung berumur pendek. Memang, ketika perancang datang berjalan dengan Talmud dari solusi UI baru untuk halaman berikutnya atau "proyek khusus", toh ada yang salah.

Pada titik ini, pengembang dihadapkan dengan pertanyaan "KERING atau tidak KERING" ? Haruskah saya menyesuaikan komponen yang ada? Ya, agar tidak menunda regresi pada kasus yang ada. Atau bertindak berdasarkan prinsip "bekerja - jangan sentuh" ​​dan menulis komponen baru dari awal. Pada saat yang sama, menggembungkan UIkit dan menyulitkan dukungan.

Jika Anda, seperti banyak orang, berada dalam situasi seperti itu, lihatlah di bawah luka!



Meskipun pengantar yang luas, gagasan menulis artikel ini datang kepada saya setelah membaca salah satu utas komentar tentang Habré. Di sana, orang-orang itu secara serius menyemprotkan tentang cara menyesuaikan komponen tombol pada React. Nah, setelah saya menyaksikan beberapa holivar semacam itu di Telegram, kebutuhan untuk menulis tentang ini akhirnya diperkuat.

Untuk mulai dengan, mari kita coba bayangkan "penyesuaian" mana yang mungkin perlu kita terapkan pada komponen.

Gaya



Pertama-tama, ini adalah penyesuaian gaya komponen. Contoh umum adalah tombol abu-abu, tetapi yang biru diperlukan. Atau sebuah tombol tanpa sudut membulat dan tiba-tiba dibutuhkan. Berdasarkan holivar yang saya baca, saya menyimpulkan bahwa ada sekitar 3 pendekatan untuk ini:

1. Gaya global


Gunakan kekuatan penuh gaya CSS global, cukup diarahkan oleh ! Penting , sehingga di luar, secara global, coba tumpang tindih gaya komponen asli. Keputusan, untuk membuatnya lebih sederhana, adalah kontroversial dan terlalu mudah. Selain itu, opsi seperti itu tidak selalu memungkinkan dan pada saat yang sama sangat melanggar enkapsulasi gaya. Kecuali tentu saja itu digunakan dalam komponen Anda.

2. Lulus kelas (gaya) dari konteks induk


Keputusan yang cukup kontroversial. Ternyata kami membuat prop khusus, seolah-olah, misalnya, kami akan menyebutnya kelas dan tepat di atas kami membenamkan kelas yang diperlukan dalam komponen.

<Button classes="btn-red btn-rounded" /> 

Tentu saja, pendekatan semacam itu hanya akan berfungsi jika komponen mendukung penerapan gaya pada kontennya dengan cara ini. Selain itu, jika komponennya sedikit lebih kompleks dan terdiri dari struktur bersarang elemen HTML, maka jelas menerapkan gaya untuk semua akan bermasalah. Jadi, mereka akan diterapkan pada elemen root dari komponen, dan kemudian, menggunakan aturan CSS, mereka entah bagaimana akan menyebar lebih jauh. Sedihnya.

3. Mengatur komponen menggunakan alat peraga


Sepertinya solusi yang paling masuk akal, tetapi pada saat yang sama solusi yang paling fleksibel. Sederhananya, kami berharap bahwa penulis komponen adalah semacam jenius dan memikirkan semua opsi di muka. Artinya, semua yang kita butuhkan dan tentukan semua alat peraga yang diperlukan untuk semua hasil yang diinginkan:

 <Button bgColor="red" rounded={true} /> 

Sepertinya itu tidak mungkin, ya? Mungkin

Perilaku




Di sini masih lebih ambigu. Pertama-tama, karena kesulitan dalam menyesuaikan perilaku komponen berasal dari tugas. Semakin kompleks komponen dan logika di dalamnya, dan juga semakin kompleks perubahan yang ingin kita buat, semakin sulit untuk melakukan perubahan itu. Beberapa jenis tautologi ternyata ... Singkatnya, Anda mengerti! ;-)

Namun, bahkan di sini, ada seperangkat alat yang membantu kami menyesuaikan komponen atau tidak. Karena kita berbicara secara khusus tentang pendekatan komponen, saya akan menyoroti alat yang berguna berikut:

1. Kerja yang nyaman dengan alat peraga


Pertama-tama, Anda harus dapat meniru set alat peraga komponen tanpa harus menggambarkan ulang set ini dan dengan mudah membuat proksi lebih lanjut.

Lebih lanjut, jika kita mencoba menambahkan beberapa perilaku ke komponen, maka, kemungkinan besar, kita perlu menggunakan seperangkat alat peraga tambahan yang tidak diperlukan oleh komponen asli. Oleh karena itu, ada baiknya untuk memotong sebagian dari alat peraga dan hanya mentransfer yang diperlukan ke komponen asli. Pada saat yang sama, menjaga semua properti disinkronkan.

Sisi sebaliknya adalah ketika kita ingin menerapkan kasus khusus perilaku komponen. Entah bagaimana untuk memperbaiki bagian dari keadaannya pada tugas tertentu.

2. Melacak siklus hidup komponen dan acara


Dengan kata lain, segala sesuatu yang terjadi di dalam komponen tidak boleh menjadi buku yang sepenuhnya tertutup. Kalau tidak, itu benar-benar menyulitkan penyesuaian perilakunya.

Maksud saya bukan pelanggaran enkapsulasi dan gangguan yang tidak terkendali di dalamnya. Komponen harus dikelola melalui api publiknya (biasanya berupa alat peraga dan / atau metode). Tetapi untuk dapat “mencari tahu” tentang apa yang terjadi di dalam dan melacak perubahan di negara bagian itu masih diperlukan.

3. Manajemen imperatif


Kami akan menganggap bahwa saya tidak memberi tahu Anda hal ini. Namun, kadang-kadang, senang bisa mendapatkan instance komponen dan secara imperatif “menarik tali”. Lebih baik untuk menghindari ini, tetapi dalam kasus yang kompleks, Anda tidak dapat melakukannya tanpanya.

Ok, semacam memilah teorinya. Secara umum, semuanya jelas, tetapi tidak semuanya jelas. Oleh karena itu, perlu mempertimbangkan setidaknya beberapa kasus nyata.

Kasing




Saya sebutkan di atas bahwa gagasan menulis artikel muncul karena holivar tentang menyesuaikan tombol. Karena itu, saya pikir akan simbolis untuk menyelesaikan kasus seperti itu. Mengubah warna atau sudut pembulatan dengan bodoh akan terlalu mudah, jadi saya mencoba membuat kasus yang sedikit lebih rumit.

Bayangkan kita memiliki komponen tertentu dari tombol dasar, yang digunakan di penjara lokasi aplikasi. Selain itu, ia mengimplementasikan beberapa perilaku dasar untuk semua tombol aplikasi, serta satu set gaya dasar, dienkapsulasi, yang, dari waktu ke waktu, disinkronkan dengan panduan UI dan semua itu.

Selanjutnya, menjadi perlu untuk memiliki komponen tambahan untuk tombol kirim ke server (tombol kirim), yang, di samping perubahan gaya, memerlukan perilaku tambahan. Misalnya, itu bisa berupa gambar dari kemajuan pengiriman, serta representasi visual dari hasil tindakan ini - berhasil atau tidak berhasil.

Mungkin terlihat seperti ini:



Tidak sulit menebak bahwa tombol dasar terletak di sebelah kiri, dan tombol kirim di sebelah kanan dalam keadaan berhasil menyelesaikan permintaan. Nah, jika kasingnya jelas - mari kita mulai!

Solusi


Saya masih tidak tahu apa yang sebenarnya menyebabkan holivar dalam keputusan React. Ternyata tidak begitu sederhana. Oleh karena itu, saya tidak akan mencoba keberuntungan saya dan menggunakan alat yang lebih akrab - SvelteJS - kerangka kerja generasi baru yang hampir sempurna untuk menyelesaikan masalah seperti itu .

Kami akan segera setuju, kami tidak akan mengganggu dengan cara apa pun kode tombol dasar. Kami berasumsi bahwa itu sama sekali tidak ditulis oleh kami, dan kodenya ditutup untuk koreksi. Dalam hal ini, komponen tombol dasar akan terlihat seperti ini:

Button.html

 <button {type} {name} {value} {disabled} {autofocus} on:click > <slot></slot> </button> <script> export default { data() { return { type: 'button', disabled: false, autofocus: false, value: '', name: '' }; } }; </script> <style> /* scoped styles */ </style> 

Dan digunakan dengan cara ini:

 <Button on:click="cancel()">Cancel</Button> 

Harap dicatat bahwa komponen tombol sangat mendasar. Ini tidak mengandung elemen tambahan atau alat peraga yang dapat membantu dalam implementasi versi komponen yang diperluas. Komponen ini bahkan tidak mendukung transfer gaya dengan alat peraga atau setidaknya beberapa jenis penyesuaian bawaan, dan semua gaya sangat terisolasi dan tidak bocor.

Membuat berdasarkan komponen ini yang lain, dengan fungsionalitas yang ditingkatkan, dan bahkan tanpa membuat perubahan, mungkin tampak seperti tugas yang mudah. Tetapi tidak ketika Anda menggunakan Svelte .

Sekarang mari kita tentukan apa yang bisa dilakukan tombol kirim:

  1. Pertama-tama, teks bingkai dan tombol harus berwarna hijau. Saat melayang, latar belakang juga harus berwarna hijau, bukan abu-abu gelap.
  2. Lebih jauh lagi, ketika sebuah tombol ditekan, itu harus “membanting” menjadi indikator putaran kemajuan.
  3. Setelah menyelesaikan proses (yang dikontrol secara eksternal), perlu bahwa status tombol dapat diubah menjadi sukses (sukses) atau tidak berhasil (kesalahan). Pada saat yang sama, tombol dari indikator harus berubah menjadi lencana hijau dengan daw, atau lencana merah dengan tanda silang.
  4. Hal ini juga diperlukan untuk dapat mengatur waktu setelah mana lencana yang sesuai akan kembali menjadi tombol dalam keadaan semula (idle).
  5. Dan tentu saja, Anda perlu melakukan semua ini di atas tombol dasar dengan menyimpan dan menerapkan semua gaya dan alat peraga dari sana.

Fuh, bukan tugas yang mudah. Pertama mari kita buat komponen baru dan bungkus dengan tombol dasar:

KirimTombol.html

 <Button> <slot></slot> </Button> <script> import Button from './Button.html'; export default { components: { Button } }; </script> 

Meskipun ini persis tombol yang sama, hanya lebih buruk - itu bahkan tidak tahu cara mem-proxy props. Ini tidak masalah, kami akan kembali ke sini nanti.

Menyesuaikan dgn mode


Sementara itu, mari kita berpikir tentang bagaimana kita dapat menata tombol baru, yaitu, mengubah warna, sesuai dengan tugas. Sayangnya, tampaknya kita tidak dapat menggunakan salah satu pendekatan yang dijelaskan di atas.

Karena gaya terisolasi di dalam tombol, masalah dengan gaya global dapat terjadi. Itu juga tidak mungkin untuk mendapatkan gaya di dalam - tombol dasar tidak mendukung fitur ini. Serta menyesuaikan penampilan dengan bantuan alat peraga. Selain itu, kami ingin semua gaya yang ditulis untuk tombol baru juga akan dienkapsulasi di dalam tombol ini dan tidak bocor.

Solusinya sangat sederhana, tetapi hanya jika Anda sudah menggunakan Svelte . Jadi, cukup tulis gaya untuk tombol baru:

 <div class="submit"> <Button> <slot></slot> </Button> </div> ... <style> .submit :global(button) { border: 2px solid #1ECD97; color: #1ECD97; } .submit :global(button:hover) { background-color: #1ECD97; color: #fff; } </style> 

Salah satu keutamaan Svelte - hal-hal sederhana harus diselesaikan dengan mudah. Pengubah khusus : global dalam versi ini akan menghasilkan CSS sedemikian rupa sehingga hanya tombol di dalam blok dengan kelas kirim yang ada di komponen ini yang akan menerima gaya yang ditentukan.

Bahkan jika markup dari jenis yang sama tiba-tiba muncul di tempat lain dalam aplikasi:

 <div class="submit"> <button>Button</button> </div> 

Gaya dari komponen SubmitButton sama sekali tidak "bocor" di sana.

Dengan menggunakan metode ini, Svelte membuatnya lebih mudah untuk menyesuaikan gaya komponen bersarang, sambil mempertahankan enkapsulasi gaya kedua komponen.

Kami melempar alat peraga dan memperbaiki perilaku


Yah, kami berurusan dengan gaya hampir secara instan dan tanpa alat peraga tambahan dan lulus kelas CSS secara langsung. Sekarang Anda perlu proksi semua alat peraga komponen Tombol melalui komponen baru. Namun, saya tidak ingin menggambarkannya lagi. Namun, sebagai permulaan, mari kita tentukan properti mana yang akan dimiliki oleh komponen baru.

Dilihat oleh tugas, SubmitButton harus memantau status, dan juga memberikan kesempatan untuk menentukan waktu tunda antara perubahan otomatis dari status sukses / kesalahan ke yang awal:

 <script> ... export default { ... data() { return { delay: 1500, status: 'idle' // loading, success, error }; } }; </script> 

Jadi, tombol baru kami akan memiliki 4 status: istirahat, unduh, sukses atau kesalahan. Selain itu, secara default, 2 status terakhir akan secara otomatis berubah ke status siaga setelah 1,5 detik.

Untuk membuang semua alat peraga yang ditransmisikan ke dalam komponen Button , tetapi pada saat yang sama memotong status dan penundaan yang jelas-jelas tidak valid untuk itu, kami akan menulis properti terhitung khusus. Dan setelah itu kita cukup menggunakan operator spread untuk "mengolesi" alat peraga yang tersisa pada komponen tertanam. Selain itu, karena kami melakukan persis tombol kirim, kami perlu memperbaiki jenis tombol sehingga tidak dapat diubah dari luar:

 <div class="submit"> <Button {...attrs} type="submit"> <slot></slot> </Button> </div> <script> ... export default { ... computed: { attrs: data => { const { delay, status, ...attrs } = data; return attrs; } }, }; </script> 

Cukup sederhana dan elegan.

Hasilnya, kami mendapatkan versi tombol dasar yang berfungsi penuh dengan gaya yang dimodifikasi. Sudah waktunya untuk menerapkan perilaku tombol baru.

Kami mengubah dan melacak status


Jadi, ketika Anda mengklik tombol SubmitButton, kita tidak hanya harus membuang acara sehingga kode pengguna dapat memprosesnya (seperti yang dilakukan pada Tombol ), tetapi juga menerapkan logika bisnis tambahan - tetapkan status unduhan. Untuk melakukan ini, cukup ambil acara dari tombol dasar ke handler Anda sendiri, lakukan apa yang Anda butuhkan dan kirimkan lebih lanjut:

 <div class="submit"> <Button {...attrs} type="submit" on:click="click(event)"> <slot></slot> </Button> </div> <script> ... export default { ... methods: { click(e) { this.set({ status: 'loading' }); this.fire('click', e); } }, }; </script> 

Selanjutnya, komponen induk tombol ini, yang mengontrol proses pengiriman data itu sendiri, dapat mengatur status pengiriman yang sesuai ( keberhasilan / kesalahan ) melalui alat peraga. Pada saat yang sama, tombol harus melacak perubahan status seperti itu, dan setelah waktu tertentu secara otomatis mengubah status ke siaga . Untuk melakukan ini, gunakan kait pembaruan on -life siklus :

 <script> ... export default { ... onupdate({ current: { status, delay }, changed }) { if (changed.status && ['success', 'error'].includes(status)) { setTimeout(() => this.set({ status: 'idle' }), delay); } }, }; </script> 

Sentuhan akhir


Ada 2 poin lagi yang tidak jelas dari tugas dan muncul selama implementasi. Pertama, agar animasi metamorfosis tombol menjadi halus, Anda harus mengubah tombol itu sendiri dengan gaya, dan bukan elemen lainnya. Untuk melakukan ini, kita dapat menggunakan hal yang sama : global , jadi tidak ada masalah. Tetapi selain itu, perlu bahwa markup di dalam tombol disembunyikan di semua status, kecuali idle .

Perlu disebutkan secara terpisah bahwa markup di dalam tombol dapat berupa apa saja dan dilemparkan ke komponen asli tombol dasar melalui slot bersarang. Namun, meskipun kedengarannya mengancam, solusinya lebih dari primitif - Anda hanya perlu membungkus slot di dalam komponen baru dalam elemen tambahan dan menerapkan gaya yang diperlukan untuk itu:

 <div class="submit"> <Button {...attrs} type="submit" on:click="click(event)"> <span><slot></slot></span> </Button> </div> ... <style> ... .submit span { transition: opacity 0.3s 0.1s; } .submit.loading span, .submit.success span, .submit.error span { opacity: 0; } ... </style> 

Selain itu, karena tombol tidak bersembunyi dari halaman, tetapi berubah seiring dengan status, alangkah baiknya menonaktifkannya pada saat pengiriman. Dengan kata lain, jika tombol kirim diatur ke dinonaktifkan menggunakan alat peraga, atau jika status tidak siaga , Anda harus menonaktifkan tombol. Untuk mengatasi masalah ini, kami menulis properti kecil yang dikomputasi isDisabled dan menerapkannya pada komponen bersarang:

 <div class="submit"> <Button {...attrs} type="submit" disabled={isDisabled}> <span><slot></slot></span> </Button> </div> <script> ... export default { ... computed: { ... isDisabled: ({ status, disabled }) => disabled || status !== 'idle' }, }; </script> 

Semuanya akan baik-baik saja, tetapi tombol dasar memiliki gaya yang membuatnya tembus dalam kondisi dinonaktifkan, tetapi kami tidak memerlukannya jika tombol hanya dinonaktifkan sementara karena perubahan status. Semua sama terjadi pada penyelamatan : global :

  .submit.loading :global(button[disabled]), .submit.success :global(button[disabled]), .submit.error :global(button[disabled]) { opacity: 1; } 

Itu saja! Tombol baru itu cantik dan siap digunakan!



Saya akan dengan sengaja menghilangkan detail implementasi animasi dan semua ini. Bukan hanya karena tidak terkait langsung dengan topik artikel, tetapi juga karena pada bagian ini demo tidak berjalan seperti yang kita inginkan. Saya tidak mempersulit tugas saya dan menerapkan solusi turnkey sepenuhnya untuk tombol seperti itu dan agak bodoh memasukkan contoh yang ditemukan di Internet.

Oleh karena itu, saya tidak menyarankan menggunakan implementasi ini dalam pekerjaan. Ingat, ini hanya demo untuk artikel ini.

Demo interaktif dan kode contoh lengkap

Jika Anda menyukai artikel ini dan ingin mempelajari lebih lanjut tentang Svelte , baca artikel lainnya. Misalnya, "Cara melakukan pencarian pengguna di GitHub tanpa React + RxJS 6 + Komposisi Ulang . " Dengarkan podcast Tahun Baru RadioJS # 54 , di mana saya berbicara secara rinci tentang apa Svelte itu , bagaimana itu "menghilang" dan mengapa itu bukan "kerangka kerja lain".

Lihatlah saluran telegram berbahasa Rusia SvelteJS . Sudah ada lebih dari dua ratus dari kami dan kami akan senang melihat Anda!

P / s

Tiba-tiba, pedoman UI berubah. Sekarang label di semua tombol aplikasi harus dalam huruf besar. Namun, kami tidak takut dengan pergantian kejadian seperti itu. Tambahkan transformasi teks: huruf besar; dalam gaya tombol dasar dan terus minum kopi.

Semoga hari kerja Anda menyenangkan!

Source: https://habr.com/ru/post/id438834/


All Articles