Patarimai ir patarimai, kaip sukurti daugkartinio naudojimo UI komponentus

Farzardo Nazifi nuotr

Šiame straipsnyje noriu pasidalinti keliais patarimais ir gudrybėmis, kuriuos naudoju kurdamas mūsų pagrindinę „frontontend“ biblioteką naudodamas „Ember.js“. Anksčiau neturėję su juo kontaktų, tai buvo puiki galimybė mokytis. Tikiuosi, kad jūs, vaikinai, mėgaujatės! Atkreipkite dėmesį, kad straipsnyje pateiktoms idėjoms parodyti yra pakankamai informacijos, kad būtų galima suprasti. Čia taip pat vartojama tam tikra „Ember.js“ terminologija, tačiau sąvokos yra skirtos struktūros agnostikai.

Tikslai

Paprasčiau tariant, bibliotekos kūrimo reikalavimai yra šie:

  1. Jis turi būti produktyvus.
  2. Ji turi būti prižiūrima.
  3. Jis turi būti nuoseklus.

Požiūriai

Sumažinkite verslo logiką

Viena iš dažniausiai pasitaikančių problemų, su kuriomis susiduriu projektuose, yra komponentai, kuriuose yra per daug logikos. Taigi, atlikti užduotis, kurios teoriškai nepatenka į jų taikymo sritį.

Prieš įgyvendinant bet kurį funkcionalumą, svarbu apibūdinti kai kurias pareigas, už kurias atsakingas komponentas.

Įsivaizduokite, kad mes kuriame sagų komponentą.

Norėčiau sugebėti:

  • Nurodykite, koks mygtuko tipas yra - pagrindinis ar įprastas
  • Informuokite mygtuką, rodomą mygtuko viduje (piktograma ir tekstas)
  • Išjunkite arba įjunkite mygtuką
  • Spustelėję atlikite kokį nors veiksmą

Turėdami šį nedidelį kontūrą, atskirkite skirtingas dalis, kurios yra šio komponento kūrimo procese. Pabandykite nustatyti, kur galėtų būti daiktai.

1 - Tipas ir turinys priklauso nuo komponento, todėl juos galima sudėti į komponento failą.

Kadangi tipas tam tikru mastu yra būtinas, pridėkime patvirtinimą, jei vertė nebuvo pateikta.

const type = get (tai, 'tipas');
const type = {
  pirminis: „btn - pagrindinis“,
  įprastas: 'btn - įprastas',
}
grįžti (tipas)? tipai [tipas]: tipai.reguliarūs;

Man patinka atvaizduoti savybes į objektą, nes tai leidžia viską išmatuoti be didelių pastangų - tuo atveju, jei mums reikia pavojaus mygtuko ar ko nors panašaus.

2 - išjungtą būseną galima rasti skirtinguose komponentuose, pavyzdžiui, įvestyje. Kad būtų išvengta pasikartojimo, tokį elgesį galima perkelti į modulį ar bet kokią bendrą struktūrą - žmonės tai vadina miksinu.

3 - Paspaudimo veiksmą galima rasti skirtinguose komponentuose. Taigi jis taip pat gali būti perkeltas į kitą failą ir jame neturėtų būti jokios logikos - paprasčiausiai paskambinkite kūrėjo atšaukimui.

Tokiu būdu galime susidaryti idėją, kokius atvejus mūsų komponentas turi išspręsti, tuo pačiu padėdamas apibrėžti bazės architektūrą, palaikančią plėtrą.

Atskira daugkartinio naudojimo vartotojo sąsaja

Tam tikros UI sąveikos būdingos skirtingiems komponentams, pvz .:

  • Įgalinti / išjungti, pvz. mygtukai, įėjimai
  • Išskleisti / trauktis - pvz. žlugti, išskleidžiamieji sąrašai
  • Rodyti / slėpti - beveik visko

Šios savybės dažnai naudojamos tik regėjimo būklei valdyti - tikiuosi.

Palaikykite nuoseklią skirtingų komponentų nomenklatūrą. Visus veiksmus, susijusius su regėjimo būsena, galima perkelti į mikserį.

/ * „UIStateMixin“ * /
išjungti () {
  rinkinys (šis, 'išjungtas', tiesa);
  grąžinti tai;
},
įjungti () {
  rinkinys (šis, 'neįgalus', klaidingas ');
  grąžinti tai;
},

Kiekvienas metodas yra atsakingas tik už tam tikro kintamojo perjungimą ir grąžina esamą grandinės sudarymo kontekstą, pavyzdžiui:

mygtuką
  .disable ()
  .showLoadingIndicator ();

Šį požiūrį galima išplėsti. Jis gali priimti skirtingus kontekstus ir valdyti išorinius kintamuosius, o ne naudoti vidinius. Pavyzdžiui:

_getCurrentDisabledAttr () {
  grįžti (isPresent (gauti (tai, 'išjungta'))))
    ? 'išjungta' / * išorinis parametras * /
    : 'isDisabled'; / * Vidinis kintamasis * /
},
įjungti (kontekstas) {
  nustatyti (kontekstas || this, this._getCurrentDisabledAttr (), false);
  grąžinti tai;
}

Pagrindinių funkcijų apibendrinimas

Kiekviename komponente yra tam tikra tvarka. Šios procedūros turi būti vykdomos neatsižvelgiant į komponento paskirtį. Pvz., Patikrinkite, ar atgalinis ryšys prieš jį suaktyvinant.

Šiuos numatytuosius metodus taip pat galima perkelti į savo derinius, pvz .:

/ * „BaseComponentMixin“ * /
_isCallbackValid (callbackName) {
  const callback = get (this, callbackName);
  
  grįžti !! (isPresent (callback) &&of typeof callback === 'function');
},
_handleCallback (atgalinis ryšys, params) {
  if (! this._isCallbackValid (callback)) {
    mesti naują klaidą (/ * pranešimas * /);
  }
  this.sendAction (atšaukimas, params);
},

Ir tada įtrauktas į komponentus.

/* Komponentas */
onClick (params) {
  this._handleCallback ('onClick', params);
}

Tai palaiko jūsų bazės architektūrą. Tai taip pat leidžia išplėsti ir netgi integruoti su trečiųjų šalių programine įranga. Bet prašau, nebūkite filosofuojantis abstrakcionistas.

Sudarantys komponentai

Kiek įmanoma venkite funkcijų perrašymo. Galima pasiekti specializaciją. Tai galima padaryti per kompoziciją ir grupavimą. Taip pat reikia suderinti mažesnius komponentus, kad būtų sukurti nauji komponentai.

Pavyzdžiui:

Pagrindiniai komponentai: mygtukas, išskleidžiamasis meniu, įvestis.
Išskleidžiamasis mygtukas => mygtukas + išskleidžiamasis mygtukas
Automatinis užbaigimas => įvestis + išskleidžiamasis meniu
Pasirinkite => įvestis (tik skaitymui) + išskleidžiamasis

Tokiu būdu kiekvienas komponentas turi savo pareigas. Kiekvienas tvarko savo būseną ir parametrus, o įvyniojimo komponentas tvarko savo specifinę logiką.

Geriausias rūpesčių atskyrimas.

Suskirstymas susirūpinimą

Kurdami sudėtingesnius komponentus, galite išskaidyti rūpesčius. Galite išskaidyti susirūpinimą tarp skirtingų komponento dalių

Tarkime, kad mes kuriame pasirinktą komponentą.

{{form-select binding = productId items = items}}
elementai = [
  {aprašymas: „produktas Nr. 1“, vertė: 1},
  {aprašymas: „produktas Nr. 2“, vertė: 2}
]

Viduje turime paprastą įvesties komponentą ir išskleidžiamąjį meniu.

{{formos įvesties įrišimas = _aprašymas}}
{{ui išskleidžiamieji elementai = elementai onSelect = (veiksmas 'selectItem')}}

Mūsų pagrindinė užduotis yra pateikti aprašą vartotojui, tačiau jis neturi jokios reikšmės mūsų programai - vertė turi.

Pasirinkdami parinktį, jūs padalinsite objektą, per vidinį kintamąjį nusiųsdami aprašą į mūsų įvestį, o reikšmę padidindami iki valdiklio, atnaujindami surištą kintamąjį.

Ši koncepcija gali būti taikoma komponentams, kuriuose surišta reikšmė turi būti pakeista, pavyzdžiui, skaičiui, automatiškai užpildyti arba pasirinkti lauką. Datos rinkėjai taip pat gali įgyvendinti šį elgesį. Jie gali atidengti datą prieš atnaujindami surištą kintamąjį, vartotojui pateikdami užmaskuotą vertę.

Rizika padidėja, kai transformacijos tampa vis sudėtingesnės. Turėdamas per daug logikos ar turėdamas palaikyti įvykius - pagalvok prieš įgyvendindamas šį požiūrį.

Išankstiniai nustatymai ir nauji komponentai

Kartais, norint palengvinti plėtrą, reikia optimizuoti komponentus ir paslaugas. Jie pristatomi iš anksto nustatytų ar naujų komponentų pavidalu.

Išankstiniai nustatymai yra parametrai. Gavę informaciją, jie nustato iš anksto nustatytas komponento vertes, supaprastindami jo deklaraciją. Tačiau nauji komponentai paprastai yra labiau specializuotos bazinių komponentų versijos.

Sunkiausia yra žinoti, kada įgyvendinti išankstinius nustatymus ar kurti naujus komponentus. Priimdamas šį sprendimą vadovaujuosi šiomis gairėmis:

Kada kurti išankstinius nustatymus

1 - pasikartojantys naudojimo įpročiai

Kartais būna, kai tam tikras komponentas pakartotinai naudojamas skirtingose ​​vietose su tais pačiais parametrais. Tokiais atvejais aš norėčiau teikti pirmenybę iš anksto nustatytiems komponentams, ypač kai bazinis komponentas turi per daug parametrų.

/ * Reguliarus įgyvendinimas * /
{{formos automatinis užpildymas
    įrišimas = produktasId
    url = "produktai" / * pateikiamas URL * /
    labelAttr = "description" / * Atributas naudojamas kaip etiketė * /
    valueAttr = "id" / * atributas naudojamas kaip vertė * /
    apiAttr = "produktas" / * Param išsiųstas paprašius * /
}}
/ * Išankstiniai nustatymai * /
{{formos automatinis užpildymas
    preset = "produktas"
    įrišimas = produktasId
}}

Iš anksto nustatytos vertės nustatomos tik tuo atveju, jei parametras nebuvo informuotas, išlaikant jo lankstumą.

/ * Naivus išankstinių nustatymų modulio įgyvendinimas * /
išankstiniai nustatymai = {
  produktas: {
    URL: „produktai“,
    labelAttr: „aprašymas“,
    valueAttr: „id“,
    apiAttr: „produktas“,
  },
}
const attrs = išankstiniai nustatymai [gauti (tai, 'iš anksto nustatyta'));
Object.keys (attrs) .forEach ((prop) => {
  if (! get (this, prop)) {
    rinkinys (tai, atrama, attrs [atrama]);
  }
});

Šis požiūris sumažina žinias, reikalingas jūsų komponentui pritaikyti. Kartu tai palengvina techninę priežiūrą, nes leidžia atnaujinti numatytąsias vertes vienoje vietoje.

2 - bazinis komponentas yra per daug sudėtingas

Kai pagrindinis komponentas, kurį naudosite kurdami konkretesnį komponentą, priima per daug parametrų. Taigi ją sukūrus atsirastų tam tikrų problemų. Pavyzdžiui:

  • Turėtumėte sušvirkšti daugiausiai (jei ne visus) parametrus nuo naujo komponento iki pagrindinio komponento. Kadangi iš jo kyla vis daugiau komponentų, bet kokie bazinio komponento atnaujinimai atspindėtų didžiulį pakeitimų kiekį. Taigi padidėja klaidų dažnis.
  • Kuo daugiau komponentų sukuriama, tuo sunkiau dokumentuoti ir įsiminti įvairius niuansus. Tai ypač pasakytina apie naujus kūrėjus.

Kada kurti naujus komponentus

1 - Funkcijų išplėtimas

Praplečiant funkcionalumą nuo paprastesnio komponento, yra perspektyvu sukurti naują komponentą. Tai padeda užkirsti kelią tam tikro komponento logikos nutekėjimui į kitą komponentą. Tai ypač naudinga įgyvendinant papildomą elgesį.

/ * Deklaracija * /
{{ui-mygtuko išskleidžiamieji elementai = elementai}}
/* Po gaubtu */
{{# ui mygtukas onClick = (veiksmas 'toggleDropdown')}}
  {{label}}  
{{/ ui-button}}
{{#if isExpanded}}
  {{ui-išskleidžiamieji elementai = elementai}}
{{/ jei}}

Aukščiau pateiktame pavyzdyje naudojamas mygtuko komponentas. Tai išplečia jo išdėstymą, kad būtų palaikoma fiksuota piktograma, kartu įtraukiant išskleidžiamąjį komponentą ir matomumo būseną.

2 - dekoravimo parametrai

Yra dar viena priežastis, kodėl reikia kurti naujus komponentus. Tai yra tada, kai reikia kontroliuoti parametrų prieinamumą arba papuošti numatytąsias reikšmes.

/ * Deklaracija * /
{{form-datepicker onFocus = (veiksmas 'doSomething')}}
/* Po gaubtu */
{{form-input onFocus = (veiksmas '_onFocus')}}
_onFocus () {
  $ (šis elementas)
    .find ('įvestis')
    .pasirinkti (); / * Pasirinkite fokusavimo lauko vertę * /
  this._handleCallback ('onFocus'); / * Suaktyvina param. Atšaukimą * /
}

Šiame pavyzdyje komponentui buvo suteikta funkcija, kuri turėjo būti vadinama, kai sufokusuojamas laukas.

Viduje jis užuot perdavęs atgalinį ryšį tiesiai į pagrindinį komponentą, jis atlieka ir vidinę funkciją. Tai atliekama tam tikra užduotis (pasirenkant lauko vertę) ir tada iškviečiamas pateiktas atgalinis ryšys.

Tai nekeičia visų parametrų, kuriuos priima bazinis įvesties komponentas. Tai padeda kontroliuoti tam tikrų funkcijų apimtį. Taip pat išvengiama nereikalingų patvirtinimų.

Mano atveju „onBlur“ įvykis buvo pakeistas kitu įvykiu - onChange. Tai suveikia, kai vartotojas užpildo lauką arba kalendoriuje pasirenka datą.

Išvada

Kurdami savo komponentus, atsižvelkite ir į savo pusę, ir į tai, kas tą komponentą naudoja kasdieniame gyvenime. Tokiu būdu laimi visi.

Geriausias rezultatas pasiekiamas iš visų grupės narių darant tai, kas geriausia sau ir grupei - Johnas Nashas

Be to, nebijokite klausti atsiliepimų. Visada rasite tai, ką galima pritaikyti.

Norėdami dar labiau sustiprinti savo programinės įrangos inžinerijos įgūdžius, rekomenduoju sekti Erico Elliotto seriją „Programinės įrangos kūrimas“. Tai nuostabu!

Na, tikiuosi, jums patiko straipsnis. Prašome atsižvelgti į šias idėjas, paversti savo idėjomis ir pasidalyti jomis su mumis!

Be to, nedvejodami susisiekite su manimi Twitter'yje @gcolombo_! Aš norėčiau išgirsti jūsų nuomonę ir net dirbti kartu.

Dėkoju!